diff --git a/Dockerfile b/Dockerfile
index b6a9cd1b..6061ad44 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,6 +22,8 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# 工作目录
WORKDIR /MaiMBot
+ENV MAIBOT_LEGACY_0X_UPGRADE_CONFIRMED=1
+
# 复制依赖列表
COPY requirements.txt .
diff --git a/README.md b/README.md
index 57130a5b..22627ced 100644
--- a/README.md
+++ b/README.md
@@ -176,6 +176,11 @@ MaiSaka 不仅仅是一个机器人,不仅仅是一个可以帮你完成任务
+### 🤝 开源项目友链
+Open Source Friends
+
+- **[AstrBot](https://github.com/AstrBotDevs/AstrBot)**: 优秀的LLM Agent项目
+
### ❤️ 特别致谢
Special Thanks
diff --git a/docker-compose.yml b/docker-compose.yml
index 0016e726..5602ae65 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -27,6 +27,7 @@ services:
# image: infinitycat/maibot:dev
environment:
- TZ=Asia/Shanghai
+ - MAIBOT_LEGACY_0X_UPGRADE_CONFIRMED=1 # Docker 无法交互确认旧版升级迁移,默认跳过确认提示
# - EULA_AGREE=1b662741904d7155d1ce1c00b3530d0d # 同意EULA
# - PRIVACY_AGREE=9943b855e72199d0f5016ea39052f1b6 # 同意EULA
ports:
diff --git a/docs-src/Bing.md b/docs-src/Bing.md
deleted file mode 100644
index 5836b157..00000000
--- a/docs-src/Bing.md
+++ /dev/null
@@ -1,51 +0,0 @@
-- **参数化与动态调整聊天行为**:
- - 将 `NormalChatInstance` 和 `HeartFlowChatInstance` 中的关键行为参数(例如:回复概率、思考频率、兴趣度阈值、状态转换条件等)提取出来,使其更易于配置。
- - 允许每个 `SubHeartflow` (即每个聊天场景) 拥有其独立的参数配置,实现"千群千面"。
- - 开发机制,使得这些参数能够被动态调整:
- - 基于外部反馈:例如,根据用户评价("话太多"或"太冷淡")调整回复频率。
- - 基于环境分析:例如,根据群消息的活跃度自动调整参与度。
- - 基于学习:通过分析历史交互数据,优化特定群聊下的行为模式。
- - 目标是让 Mai 在不同群聊中展现出更适应环境、更个性化的交互风格。
-
-- **动态 Prompt 生成与人格塑造**:
- - 当前 Prompt (提示词) 相对静态。计划实现动态或半结构化的 Prompt 生成。
- - Prompt 内容可根据以下因素调整:
- - **人格特质**: 通过参数化配置(如友善度、严谨性等),影响 Prompt 的措辞、语气和思考倾向,塑造更稳定和独特的人格。
- - **当前情绪**: 将实时情绪状态融入 Prompt,使回复更符合当下心境。
- - 目标:提升 `HeartFlowChatInstance` (HFC) 回复的多样性、一致性和真实感。
- - 前置:需要重构 Prompt 构建逻辑,可能引入 `PromptBuilder` 并提供标准接口 (认为是必须步骤)。
-
-
-- **增强工具调用能力 (Enhanced Tool Usage)**:
- - 扩展 `HeartFlowChatInstance` (HFC) 可用的工具集。
- - 考虑引入"元工具"或分层工具机制,允许 HFC 在需要时(如深度思考)访问更强大的工具,例如:
- - 修改自身或其他 `SubHeartflow` 的聊天参数。
- - 请求改变 Mai 的全局状态 (`MaiState`)。
- - 管理日程或执行更复杂的分析任务。
- - 目标:提升 HFC 的自主决策和行动能力,即使会增加一定的延迟。
-
-- **标准化人设生成 (Standardized Persona Generation)**:
- - **目标**: 解决手动配置 `人设` 文件缺乏标准、难以全面描述个性的问题,并生成更丰富、可操作的人格资源。
- - **方法**: 利用大型语言模型 (LLM) 辅助生成标准化的、结构化的人格**资源包**。
- - **生成内容**: 不仅生成描述性文本(替代现有 `individual` 配置),还可以同时生成与该人格配套的:
- - **相关工具 (Tools)**: 该人格倾向于使用的工具或能力。
- - **初始记忆/知识库 (Memories/Knowledge)**: 定义其背景和知识基础。
- - **核心行为模式 (Core Behavior Patterns)**: 预置一些典型的行为方式,可作为行为学习的起点。
- - **实现途径**:
- - 通过与 LLM 的交互式对话来定义和细化人格及其配套资源。
- - 让 LLM 分析提供的文本材料(如小说、背景故事)来提取人格特质和相关信息。
- - **优势**: 替代易出错且标准不一的手动配置,生成更丰富、一致、包含配套资源且易于系统理解和应用的人格包。
-
-
-- **探索高级记忆检索机制 (GE 系统概念):**
- - 研究超越简单关键词/近期性检索的记忆模型。
- - 考虑引入基于事件关联、相对时间线索和绝对时间锚点的检索方式。
- - 可能涉及设计新的事件表示或记忆结构。
-
-- **基于人格生成预设知识:**
- - 开发利用 LLM 和人格配置生成背景知识的功能。
- - 这些知识应符合角色的行为风格和可能的经历。
- - 作为一种"冷启动"或丰富角色深度的方式。
-
-
-1.更nb的工作记忆,直接开一个play_ground,通过llm进行内容检索,这个play_ground可以容纳巨量信息,并且十分通用化,十分好。
\ No newline at end of file
diff --git a/docs-src/lpmm_parameters_guide.md b/docs-src/lpmm_parameters_guide.md
deleted file mode 100644
index 5d190589..00000000
--- a/docs-src/lpmm_parameters_guide.md
+++ /dev/null
@@ -1,156 +0,0 @@
-# LPMM 关键参数调节指南(进阶版)
-
-> 本文是对 `config/bot_config.toml` 中 `[lpmm_knowledge]` 段的补充说明。
-> 如果你只想使用默认配置,可以不改这些参数,脚本仍然可以正常工作。
->
-> 重要提醒:无论是修改 `[lpmm_knowledge]` 段的参数,还是通过脚本导入 / 删除 LPMM 知识库数据,主程序都需要重启(或在内部调用一次 `lpmm_start_up()`)后,新的参数和知识才会真正生效到聊天侧。
-
-所有与 LPMM 相关的参数,都集中在:
-
-```toml
-[lpmm_knowledge] # lpmm知识库配置
-enable = true
-lpmm_mode = "agent"
-...
-```
-
-下面按功能将常用参数分为三组介绍。
-
----
-
-## 一、检索相关参数(影响答案质量与风格)
-
-```toml
-qa_relation_search_top_k = 10 # 关系检索TopK
-qa_relation_threshold = 0.5 # 关系阈值,相似度高于该值才认为“命中关系”
-qa_paragraph_search_top_k = 1000 # 段落检索TopK,越小可能影响召回
-qa_paragraph_node_weight = 0.05 # 段落节点权重,在图检索&PPR中的权重
-qa_ent_filter_top_k = 10 # 实体过滤TopK
-qa_ppr_damping = 0.8 # PPR阻尼系数
-qa_res_top_k = 3 # 最终提供给问答模型的段落数
-```
-
-- `qa_relation_search_top_k`
- 控制“最多考虑多少条关系向量候选”。
- - 数值大:召回更全面,但略慢;
- - 数值小:更快,可能遗漏部分隐含关系。
-
-- `qa_relation_threshold`
- 关系相似度的阈值:
- - 数值高:只信任非常相关的关系,系统更可能退化为纯段落向量检索;
- - 数值低:图结构影响更大,适合实体关系较丰富的场景。
-
-- `qa_paragraph_search_top_k`
- 控制“最多考虑多少段落候选”。
- - 太小:可能召回不全,导致答案缺失;
- - 太大:略微增加计算量,一般 1000 为安全默认。
-
-- `qa_paragraph_node_weight`
- 文段节点在图检索中的权重:
- - 数值大:更依赖段落向量相似度(传统向量检索);
- - 数值小:更依赖图结构和实体网络。
-
-- `qa_ppr_damping`
- Personalized PageRank 的阻尼系数:
- - 通常保持在 0.8 左右即可;
- - 越接近 1:偏向长路径探索,结果更发散;
- - 略低:更集中在与问题直接相关的节点附近。
-
-- `qa_res_top_k`
- LPMM 最终会把相关度最高的前 `qa_res_top_k` 条段落组合成“知识上下文”给问答模型。
- - 太多:增加模型负担、阅读更多文字;
- - 太少:信息不够充分,一般 3–5 比较平衡。
-
-> 调参建议:
-> - 优先在 `qa_relation_threshold`、`qa_paragraph_node_weight` 上做小幅调整;
-> - 每次调整后,用 `scripts/test_lpmm_retrieval.py` 跑一遍固定问题,感受回答变化。
-
----
-
-## 二、性能与硬件相关参数
-
-```toml
-embedding_dimension = 1024 # 嵌入向量维度,应与模型输出维度一致
-max_embedding_workers = 12 # 嵌入/抽取并发线程数
-embedding_chunk_size = 16 # 每批嵌入的条数
-info_extraction_workers = 3 # 实体抽取同时执行线程数
-enable_ppr = true # 是否启用PPR,低配机器可关闭
-```
-
-- `embedding_dimension`
- 必须与所选嵌入模型的输出维度一致(比如 768、1024 等)。**不要随意修改,除非你知道你在做什么!!!**
-
-- `max_embedding_workers`
- 决定导入/抽取阶段的并行线程数:
- - 机器配置好:可以适当调大,加快导入速度;
- - 机器配置弱:建议调低(如 2 或 4),避免 CPU 长时间 100%。
-
-- `embedding_chunk_size`
- 每批发送给嵌入 API 的段落数量:
- - 数值大:请求次数少,但单次请求更“重”;
- - 数值小:请求次数多,但对网络和 API 的单次压力小。
-
-- `info_extraction_workers`
- `scripts/info_extraction.py` 中实体抽取的并行线程数:
- - 使用 Pro/贵价模型时建议不要太大,避免并行费用过高;
- - 一般 2–4 就能取得较好平衡。
-
-- `enable_ppr`
- 是否启用个性化 PageRank(PPR)图检索:
- - `true`:检索会结合向量+知识图,效果更好,但略慢;
- - `false`:只用向量检索,牺牲一定效果,性能更稳定。
-
-
-> 调参建议:
-> - 若导入/检索阶段机器明显“顶不住”(>=1MB的大文本,且分配配置<4C),优先调低:
-> - `max_embedding_workers`
-> - `embedding_chunk_size`
-> - `info_extraction_workers`
-> - 或暂时将 `enable_ppr = false` (除非真的出现问题,否则不建议禁用此项,大幅影响检索效果)
-> - 调整后重新执行导入或检索,观察日志与系统资源占用。
-
-> 小提示:每次大改参数或批量删除知识后,建议用
-> - `scripts/test_lpmm_retrieval.py` 看回答风格是否如预期;
-> - 如需确认当前磁盘数据能否正常初始化,可执行 `scripts/refresh_lpmm_knowledge.py` 做一次快速自检。
-
----
-
-## 三、开启/关闭 LPMM 与模式说明
-
-```toml
-enable = true # 是否开启lpmm知识库
-lpmm_mode = "agent" # 可选 classic / agent
-```
-
-- `enable`
- - `true`:LPMM 知识库启用,检索和问答会使用知识库;
- - `false`:LPMM 完全关闭,脚本仍可导入/删除数据,但对聊天问答不生效。
-
-- `lpmm_mode`
- - `classic`:传统模式,仅使用 LPMM 知识库本身;
- - `agent`:与新的记忆系统联动,用于更复杂的记忆+知识混合场景。
-
-> 修改 `enable` 或 `lpmm_mode` 后,需要重启主程序,让配置生效。
-
----
-
-## 四、推荐的调参流程
-
-1. **保持默认配置,先跑一轮完整流程**
- - 导入 → `inspect_lpmm_global.py` → `test_lpmm_retrieval.py`;
- - 记录当前“答案风格”和“响应速度”。
-
-2. **每次只调整一到两个参数**
- - 例如先调 `qa_relation_threshold`、`qa_paragraph_node_weight`;
- - 或在性能不佳时调整 `max_embedding_workers`、`enable_ppr`。
-
-3. **调整后重复同一组测试问题**
- - 使用 `scripts/test_lpmm_retrieval.py`;
- - 对比不同配置下的答案,选择更符合需求的组合。
-
-4. **出现“怎么调都不对”时**
- - 将 `[lpmm_knowledge]` 段恢复为仓库中的默认配置;
- - 重启主程序,即可回到“出厂设置”。
-
-通过本指南中的参数调节,你可以在“检索质量”“响应速度”“系统资源占用”之间找到适合自己麦麦和机器的平衡点!
-
diff --git a/docs-src/lpmm_pipelines_guide.md b/docs-src/lpmm_pipelines_guide.md
deleted file mode 100644
index 6539a2fc..00000000
--- a/docs-src/lpmm_pipelines_guide.md
+++ /dev/null
@@ -1,326 +0,0 @@
-## LPMM 知识库流水线使用指南(命令行版)
-
-本文档介绍如何使用 `scripts/lpmm_manager.py` 及相关子脚本,完成 **导入 / 删除 / 自检 / 刷新 / 回归测试** 等常见流水线操作,并说明各参数在交互式与非交互(脚本化)场景下的用法。
-
-所有命令均假设在项目根目录 `MaiBot/` 下执行:
-
-```bash
-cd MaiBot
-```
-
----
-
-## 1. 管理脚本总览:`scripts/lpmm_manager.py`
-
-### 1.1 基本用法
-
-```bash
-python scripts/lpmm_manager.py [--interactive] [-a ACTION] [--non-interactive] [-- ...子脚本参数...]
-```
-
-- `--interactive` / `-i`:进入交互式菜单模式(推荐人工运维时使用)。
-- `--action` / `-a`:直接执行指定操作(非交互入口),可选值:
- - `prepare_raw`:预处理 `data/lpmm_raw_data/*.txt`。
- - `info_extract`:信息抽取,生成 OpenIE JSON 批次。
- - `import_openie`:导入 OpenIE 批次到向量库与知识图。
- - `delete`:删除/回滚知识(封装 `delete_lpmm_items.py`)。
- - `batch_inspect`:检查指定 OpenIE 批次的存在情况。
- - `global_inspect`:全库状态统计。
- - `refresh`:刷新 LPMM 磁盘数据到内存。
- - `test`:检索效果回归测试。
- - `full_import`:一键执行「预处理原始语料 → 信息抽取 → 导入 → 刷新」。
-- `--non-interactive`:
- - 启用 **非交互模式**:`lpmm_manager` 自身不会再调用 `input()` 询问确认;
- - 同时自动向子脚本透传 `--non-interactive`(若子脚本支持),用于在 CI / 定时任务中实现无人值守。
-- `--` 之后的内容会原样传递给对应子脚本的 `main()`,用于设置更细粒度参数。
-
-> 注意:`--interactive` 与 `--non-interactive` 互斥,不能同时使用。
-
----
-
-## 2. 典型流水线一:全量导入(从原始 txt 到可用 LPMM)
-
-### 2.1 前置条件
-
-- 将待导入的原始文本放入:
-
-```text
-data/lpmm_raw_data/*.txt
-```
-
-- 文本按「空行分段」,每个段落为一条候选知识。
-
-### 2.2 一键全流程(交互式)
-
-```bash
-python scripts/lpmm_manager.py --interactive
-```
-
-菜单中依次:
-
-1. 选择 `9. full_import`(预处理 → 信息抽取 → 导入 → 刷新)。
-2. 按提示确认可能的费用与时间消耗。
-3. 等待脚本执行完成。
-
-### 2.3 一键全流程(非交互 / CI 友好)
-
-```bash
-python scripts/lpmm_manager.py -a full_import --non-interactive
-```
-
-执行顺序:
-
-1. `prepare_raw`:调用 `raw_data_preprocessor.load_raw_data()`,统计段落与去重哈希数。
-2. `info_extract`:调用 `info_extraction.main(--non-interactive)`,从 `data/lpmm_raw_data` 读取段落,生成 OpenIE JSON 并写入 `data/openie/`。
-3. `import_openie`:调用 `import_openie.main(--non-interactive)`,导入 OpenIE 批次到嵌入库与 KG。
-4. `refresh`:调用 `refresh_lpmm_knowledge.main()`,刷新 LPMM 知识库到内存。
-
-在 `--non-interactive` 模式下:
-
-- 若 `data/lpmm_raw_data` 中没有 `.txt` 文件,或 `data/openie` 中没有 `.json` 文件,将直接报错退出,并在日志中说明缺少的目录/文件。
-- 若 OpenIE 批次中存在非法文段,导入脚本会 **直接报错退出**,不会卡在交互确认上。
-
----
-
-## 3. 典型流水线二:分步导入
-
-若需要逐步调试或只执行部分步骤,可以分开调用:
-
-### 3.1 预处理原始语料:`prepare_raw`
-
-```bash
-python scripts/lpmm_manager.py -a prepare_raw
-```
-
-行为:
-- 使用 `raw_data_preprocessor.load_raw_data()` 读取 `data/lpmm_raw_data/*.txt`;
-- 输出段落总数与去重后的哈希数,供人工检查原始数据质量。
-
-### 3.2 信息抽取:`info_extract`
-
-#### 交互式(带费用提示)
-
-```bash
-python scripts/lpmm_manager.py -a info_extract
-```
-
-脚本会:
-- 打印预计费用/时间提示;
-- 询问 `确认继续执行?(y/n)`;
-- 然后开始从 `data/lpmm_raw_data` 中读取段落,调用 LLM 提取实体与三元组,并生成 OpenIE JSON。
-
-#### 非交互式(无人工确认)
-
-```bash
-python scripts/lpmm_manager.py -a info_extract --non-interactive
-```
-
-行为差异:
-- 跳过`确认继续执行`的交互提示,直接开始抽取;
-- 若 `data/lpmm_raw_data` 下没有 `.txt` 文件,会打印告警并以错误方式退出。
-
-### 3.3 导入 OpenIE 批次:`import_openie`
-
-#### 交互式
-
-```bash
-python scripts/lpmm_manager.py -a import_openie
-```
-
-脚本会:
-- 提示导入开销与资源占用情况;
-- 询问是否继续;
-- 调用 `OpenIE.load()` 加载批次,再将其导入嵌入库与 KG。
-
-#### 非交互式
-
-```bash
-python scripts/lpmm_manager.py -a import_openie --non-interactive
-```
-
-- 跳过导入开销确认;
-- 若数据存在非法文段:
- - 在交互模式下会询问是否删除这些非法文段并继续;
- - 在非交互模式下,会直接 `logger.error` 并 `sys.exit(1)`,防止导入不完整数据。
-
-> 提示:当前 `OpenIE.load()` 仍可能在内部要求你选择具体批次文件,若需完全无交互的导入,可后续扩展为显式指定文件路径。
-
-### 3.4 刷新 LPMM 知识库:`refresh`
-
-```bash
-python scripts/lpmm_manager.py -a refresh
-# 或
-python scripts/lpmm_manager.py -a refresh --non-interactive
-```
-
-两者行为相同:
-- 调用 `refresh_lpmm_knowledge.main()`,内部执行 `lpmm_start_up()`;
-- 日志中输出当前向量与 KG 规模,验证导入是否成功。
-
----
-
-## 4. 典型流水线三:删除 / 回滚
-
-删除操作通过 `lpmm_manager.py -a delete` 封装 `scripts/delete_lpmm_items.py`。
-
-### 4.1 交互式删除(推荐人工操作)
-
-```bash
-python scripts/lpmm_manager.py --interactive
-```
-
-菜单中选择:
-
-1. `4. delete - 删除/回滚知识`
-2. 再选择删除方式:
- - 按哈希文件(`--hash-file`)
- - 按 OpenIE 批次(`--openie-file`)
- - 按原始语料 + 段落索引(`--raw-file + --raw-index`)
- - 按关键字搜索现有段落(`--search-text`)
-3. 管理脚本会根据你的选择自动拼好常用参数(是否删除实体/关系、是否删除孤立实体、是否 dry-run、是否自动确认等),最后调用 `delete_lpmm_items.py` 执行。
-
-### 4.2 非交互删除(CI / 脚本场景)
-
-#### 示例:按哈希文件删除(带完整保护参数)
-
-```bash
-python scripts/lpmm_manager.py -a delete --non-interactive -- \
- --hash-file data/lpmm_delete_hashes.txt \
- --delete-entities \
- --delete-relations \
- --remove-orphan-entities \
- --max-delete-nodes 2000 \
- --yes
-```
-
-- `--non-interactive`(manager):禁止任何 `input()` 询问;
-- 子脚本 `delete_lpmm_items.py` 中:
- - `--hash-file`:指定待删段落哈希列表;
- - `--delete-entities` / `--delete-relations` / `--remove-orphan-entities`:同步清理实体与关系;
- - `--max-delete-nodes`:单次删除节点数上限,避免误删过大规模;
- - `--yes`:跳过终极确认,适合已验证的自动流水线。
-
-#### 按 OpenIE 批次删除(常用于批次回滚)
-
-```bash
-python scripts/lpmm_manager.py -a delete --non-interactive -- \
- --openie-file data/openie/2025-01-01-12-00-openie.json \
- --delete-entities \
- --delete-relations \
- --remove-orphan-entities \
- --yes
-```
-
-### 4.3 非交互模式下的安全限制
-
-在 `delete_lpmm_items.py` 中:
-
-- 若使用 `--search-text`,需要用户通过输入序号选择要删条目;
- - 在 `--non-interactive` 模式下,这一步会直接报错退出,提示改用 `--hash-file / --openie-file / --raw-file` 等纯参数方式。
-- 若未指定 `--yes`:
- - 非交互模式下会报错退出,提示「非交互模式且未指定 --yes,出于安全考虑删除操作已被拒绝」。
-
----
-
-## 5. 典型流水线四:自检与状态检查
-
-### 5.1 检查指定 OpenIE 批次状态:`batch_inspect`
-
-```bash
-python scripts/lpmm_manager.py -a batch_inspect -- --openie-file data/openie/xx.json
-```
-
-输出该批次在当前库中的:
-- 段落向量数量 / KG 段落节点数量;
-- 实体向量数量 / KG 实体节点数量;
-- 关系向量数量;
-- 少量仍存在的样例内容。
-
-常用于:
-- 导入后确认是否完全成功;
-- 删除后确认是否完全回滚。
-
-### 5.2 查看整库状态:`global_inspect`
-
-```bash
-python scripts/lpmm_manager.py -a global_inspect
-```
-
-输出:
-- 段落 / 实体 / 关系向量条数;
-- KG 节点/边总数,段落节点数、实体节点数;
-- 实体计数表 `ent_appear_cnt` 的条目数;
-- 少量剩余段落/实体样例,便于快速 sanity check。
-
----
-
-## 6. 典型流水线五:检索效果回归测试
-
-### 6.1 使用默认测试用例
-
-```bash
-python scripts/lpmm_manager.py -a test
-```
-
-- 调用 `test_lpmm_retrieval.py` 内置的 `DEFAULT_TEST_CASES`;
-- 对每条用例输出:
- - 原始结果;
- - 状态(`PASS` / `WARN` / `NO_HIT` / `ERROR`);
- - 期望关键字与命中关键字列表。
-
-### 6.2 自定义测试问题与期望关键字
-
-```bash
-python scripts/lpmm_manager.py -a test -- --query "LPMM 是什么?" \
- --expect-keyword 哈希列表 \
- --expect-keyword 删除脚本
-```
-
-也可以直接调用子脚本:
-
-```bash
-python scripts/test_lpmm_retrieval.py \
- --query "LPMM 是什么?" \
- --expect-keyword 哈希列表 \
- --expect-keyword 删除脚本
-```
-
----
-
-## 7. 推荐组合示例
-
-### 7.1 导入 + 刷新 + 简单回归
-
-```bash
-# 1. 执行全量导入(支持非交互)
-python scripts/lpmm_manager.py -a full_import --non-interactive
-
-# 2. 使用内置用例做一次检索回归
-python scripts/lpmm_manager.py -a test
-```
-
-### 7.2 批次回滚 + 自检
-
-```bash
-TARGET_BATCH=data/openie/2025-01-01-12-00-openie.json
-
-# 1. 按批次删除(非交互)
-python scripts/lpmm_manager.py -a delete --non-interactive -- \
- --openie-file "$TARGET_BATCH" \
- --delete-entities \
- --delete-relations \
- --remove-orphan-entities \
- --yes
-
-# 2. 检查该批次是否彻底删除
-python scripts/lpmm_manager.py -a batch_inspect -- --openie-file "$TARGET_BATCH"
-
-# 3. 查看全库状态
-python scripts/lpmm_manager.py -a global_inspect
-```
-
----
-
-如需扩展更多流水线(例如「导入特定批次后自动跑自定义测试用例」),可以在 `scripts/lpmm_manager.py` 中新增对应的 `ACTION_INFO` 条目和 `run_action` 分支,或直接在 CI / shell 脚本中串联上述命令。该管理脚本已支持参数化与非交互调用,适合作为二次封装的基础入口。
-
-
diff --git a/docs-src/lpmm_user_guide.md b/docs-src/lpmm_user_guide.md
deleted file mode 100644
index 147ebcab..00000000
--- a/docs-src/lpmm_user_guide.md
+++ /dev/null
@@ -1,411 +0,0 @@
-# LPMM 知识库脚本使用指南(零基础用户版)
-
-本指南面向不熟悉命令行和代码的 C 端用户,帮助你完成:
-
-- LPMM 知识库的初始部署(从本地 txt 到可检索知识库)
-- 安全删除知识(按批次、按原文、按哈希、按关键字)
-- 导入 / 删除后的自检与检索效果验证
-
-> 说明:本文默认你已经完成 MaiBot 的基础安装,并能在项目根目录打开命令行终端。
-> 重要提醒:每次使用导入 / 删除相关脚本(如 `import_openie.py`、`delete_lpmm_items.py`)修改 LPMM 知识库后,聊天机器人 / WebUI 端要想看到最新知识,需要重启主程序,或在主程序内部显式调用一次 `lpmm_start_up()` 重新初始化 LPMM
-
----
-。
-
-
-## 一、需要用到的脚本一览
-
-在项目根目录(`MaiBot-dev`)下,这些脚本是 LPMM 相关的“工具箱”:
-
-- 导入相关:
- - `scripts/raw_data_preprocessor.py`
- 从 `data/lpmm_raw_data` 目录读取 `.txt` 文件,按空行拆分为一个个段落,并做去重。
- - `scripts/info_extraction.py`
- 调用大模型,从每个段落里抽取实体和三元组,生成中间的 OpenIE JSON 文件。
- - `scripts/import_openie.py`
- 把 `data/openie` 目录中的 OpenIE JSON 文件导入到 LPMM 知识库(向量库 + 知识图)。
-- 删除相关:
- - `scripts/delete_lpmm_items.py`
- LPMM 知识库删除入口,支持按批次、按原始文本段落、按哈希列表、按关键字模糊搜索删除。
-- 自检相关:
- - `scripts/inspect_lpmm_global.py`
- 查看整个知识库的当前状态:段落/实体/关系条数、知识图节点/边数量、示例内容等。
- - `scripts/inspect_lpmm_batch.py`
- 针对某个 OpenIE JSON 批次,检查它在向量库和知识图中的“残留情况”(导入与删除前后对比)。
- - `scripts/test_lpmm_retrieval.py`
- 使用几条预设问题测试 LPMM 检索能力,帮助你判断知识库是否正常工作。
- - `scripts/refresh_lpmm_knowledge.py`
- 手动重新加载 `data/embedding` 和 `data/rag` 到内存,用来确认当前磁盘上的 LPMM 知识库能正常初始化。
-
-> 注意:所有命令示例都假设你已经在虚拟环境中,命令行前缀类似 `(.venv)`,并且当前目录是项目根目录。
-
----
-
-## 二、LPMM 知识库的初始部署
-
-### 2.1 准备原始 txt 文本
-
-1. 把要导入的知识文档放到:
-
- ```text
- data/lpmm_raw_data
- ```
-
-2. 文件要求:
-
- - 必须是 `.txt` 文件,建议使用 UTF-8 编码;
- - 用**空行**分隔段落:一段话后空一行,即视为一条独立知识。
-
-示例文件:
-
-- `data/lpmm_raw_data/lpmm_large_sample.txt`:仓库内已经提供了一份大样本测试文本,可以直接用来练习。
-
-### 2.2 第一步:预处理原始文本(拆段 + 去重)
-
-在项目根目录执行:
-
-```bash
-.\.venv\Scripts\python.exe scripts/raw_data_preprocessor.py
-```
-
-成功时通常会看到日志类似:
-
-- 正在处理文件: `lpmm_large_sample.txt`
-- 共读取到 XX 条数据
-
-这一步不会调用大模型,仅做拆段和去重。
-
-### 2.3 第二步:进行信息抽取(生成 OpenIE JSON)
-
-执行:
-
-```bash
-.\.venv\Scripts\python.exe scripts/info_extraction.py
-```
-
-你会看到一个“重要操作确认”提示,说明:
-
-- 信息抽取会调用大模型,消耗 API 费用和时间;
-- 如果确认无误,输入 `y` 回车继续。
-
-提取过程中可能出现:
-
-- 类似“模型 ... 网络错误(可重试)”这样的日志;
- 这表示脚本在遇到网络问题时自动重试,一般无需手动干预。
-
-运行结束后,会有类似提示:
-
-```text
-信息提取结果已保存到: data/openie/11-27-10-06-openie.json
-```
-
-- 请记住这个文件名,比如:`11-27-10-06-openie.json`
- 接下来我们会用 `` 来代指这类文件。
-
-### 2.4 第三步:导入 OpenIE 数据到 LPMM 知识库
-
-执行:
-
-```bash
-.\.venv\Scripts\python.exe scripts/import_openie.py
-```
-
-这个脚本会:
-
-- 从 `data/openie` 目录读取所有 `*.json` 文件,并合并导入;
-- 将新段落的嵌入向量写入 `data/embedding`;
-- 将三元组构建为知识图写入 `data/rag`。
-
-> 提示:如果你希望“只导入某几批数据”,可以暂时把不需要的 JSON 文件移出 `data/openie`,导入结束后再移回。
-
-### 2.5 第四步:全局自检(确认导入成功)
-
-执行:
-
-```bash
-.\.venv\Scripts\python.exe scripts/inspect_lpmm_global.py
-```
-
-你会看到类似输出:
-
-- 段落向量条数: `52`
-- 实体向量条数: `260`
-- 关系向量条数: `299`
-- KG 节点总数 / 边总数 / 段落节点数 / 实体节点数
-- 若干条示例段落与实体内容预览
-
-只要这些数字大于 0,就表示 LPMM 知识库已经有可用的数据了。
-
-### 2.6 第五步:用脚本测试 LPMM 检索效果(可选但推荐)
-
-执行:
-
-```bash
-.\.venv\Scripts\python.exe scripts/test_lpmm_retrieval.py
-```
-
-脚本会:
-
-- 自动初始化 LPMM(加载向量库与知识图);
-- 用几条预设问题查询 LPMM;
-- 打印原始检索结果和关键词命中情况。
-
-你可以通过观察“RAW RESULT”里的内容,粗略判断:
-
-- 能否命中与问题高度相关的知识;
-- 删除或导入新知识后,回答内容是否发生变化。
-
----
-
-## 三、安全删除知识的几种方式
-
-> 强烈建议:删除前先备份以下目录,以便“回档”:
->
-> - `data/embedding`(向量库)
-> - `data/rag`(知识图)
-
-所有删除操作使用同一个脚本:
-
-```bash
-.\.venv\Scripts\python.exe scripts/delete_lpmm_items.py [参数...]
-```
-
-脚本特点:
-
-- 删除前会打印“待删除段落数量 / 实体数量 / 关系数量 / 预计删除节点数”等摘要;
-- 需要你输入大写 `YES` 确认才会真正执行;
-- 支持多种删除策略,可灵活组合。
-
-### 3.1 按批次删除(推荐:整批回滚)
-
-适用场景:某次导入的整批知识有问题,希望整体回滚。
-
-1. 删除前,先检查该批次状态:
-
- ```bash
- .\.venv\Scripts\python.exe scripts/inspect_lpmm_batch.py ^
- --openie-file data/openie/.json
- ```
-
- 你会看到该批次:
-
- - 段落:总计多少条、向量库剩余多少、KG 中剩余多少;
- - 实体、关系的类似统计;
- - 少量示例段落/实体内容预览。
-
-2. 确认无误后,按批次删除:
-
- ```bash
- .\.venv\Scripts\python.exe scripts/delete_lpmm_items.py ^
- --openie-file data/openie/.json ^
- --delete-entities --delete-relations --remove-orphan-entities
- ```
-
- 参数含义:
-
- - `--delete-entities`:删除该批次涉及的实体向量;
- - `--delete-relations`:删除该批次涉及的关系向量;
- - `--remove-orphan-entities`:顺带清理删除后不再参与任何边的“孤立实体”节点。
-
-3. 删除后再检查:
-
- ```bash
- .\.venv\Scripts\python.exe scripts/inspect_lpmm_batch.py ^
- --openie-file data/openie/.json
-
- .\.venv\Scripts\python.exe scripts/inspect_lpmm_global.py
- ```
-
- 若批次检查显示“向量库剩余 0 / KG 中剩余 0”,则说明该批次已被彻底删除。
-
-### 3.2 按原始文本段落删除(精确定位某一段)
-
-适用场景:某个原始 txt 的特定段落写错了,只想删这段对应的知识。
-
-命令示例:
-
-```bash
-.\.venv\Scripts\python.exe scripts/delete_lpmm_items.py ^
- --raw-file data/lpmm_raw_data/lpmm_large_sample.txt ^
- --raw-index 2
-```
-
-说明:
-
-- `--raw-index` 从 1 开始计数,可用逗号多选,例如:`1,3,5`;
-- 脚本会展示该段落的内容预览和哈希值,再请求你确认。
-
-### 3.3 按哈希列表删除(进阶用法)
-
-适用场景:你有一份“需要删除的段落哈希列表”(比如从其他系统导出)。
-
-示例哈希列表文件:
-
-- `data/openie/lpmm_delete_test_hashes.txt`
-
-命令:
-
-```bash
-.\.venv\Scripts\python.exe scripts/delete_lpmm_items.py ^
- --hash-file data/openie/lpmm_delete_test_hashes.txt
-```
-
-说明:
-
-- 文件中每行一条,可以是 `paragraph-xxxx` 或纯哈希,脚本会自动识别;
-- 适合“精确控制删除哪些段落”,但准备哈希列表需要一定技术基础。
-
-### 3.4 按关键字模糊搜索删除(对非技术用户最友好)
-
-适用场景:只知道某段话里包含某个关键词,不知道它在哪个 txt 或批次里。
-
-示例 1:删除与“近义词扩展”相关的段落
-
-```bash
-.\.venv\Scripts\python.exe scripts/delete_lpmm_items.py --search-text "近义词扩展" --search-limit 5
-```
-
-示例 2:删除与“LPMM”强相关的一些段落
-
-```bash
-.\.venv\Scripts\python.exe scripts/delete_lpmm_items.py --search-text "LPMM" --search-limit 20
-
-```
-
-执行过程:
-
-1. 脚本在当前段落库中查找包含该关键字的段落;
-2. 列出前 N 条候选(`--search-limit` 决定数量);
-3. 提示你输入要删除的序号列表,例如:`1,2,5`;
-4. 再次提示你输入 `YES` 确认,才会真正执行删除。
-
-> 建议:
->
-> - 第一次使用时可以先加 `--dry-run` 看看效果:
-> ```bash
-> .\.venv\Scripts\python.exe scripts/delete_lpmm_items.py ^
-> --search-text "LPMM" ^
-> --search-limit 20 ^
-> --dry-run
-> ```
-> - 确认候选列表确实是你要删的内容后,再去掉 `--dry-run` 正式执行。
-
----
-
-## 四、自检:如何确认导入 / 删除是否“生效”
-
-### 4.1 全局状态检查
-
-每次导入或删除之后,建议跑一次:
-
-```bash
-.\.venv\Scripts\python.exe scripts/inspect_lpmm_global.py
-```
-
-你可以在这里看到:
-
-- 段落向量条数、实体向量条数、关系向量条数;
-- 知识图的节点总数、边总数、段落节点和实体节点数量;
-- 若干条“剩余段落示例”和“剩余实体示例”。
-
-观察方式:
-
-- 导入后:数字应该明显上升(说明新增数据生效);
-- 删除后:数字应该明显下降(说明删除操作生效)。
-
-### 4.2 某个批次的局部状态
-
-如果你想确认“某一个 OpenIE 文件对应的那一批知识”是否存在,可以使用:
-
-```bash
-.\.venv\Scripts\python.exe scripts/inspect_lpmm_batch.py --openie-file data/openie/.json
-```
-
-输出中会包含:
-
-- 该批次的段落 / 实体 / 关系的总数;
-- 在向量库中还剩多少条,在 KG 中还剩多少条;
-- 若干条仍存在的段落/实体示例。
-
-典型用法:
-
-- 导入后立刻检查一次:确认这一批已经“写入”;
-- 删除后再检查一次:确认这一批是否已经“清空”。
-
-### 4.3 检索效果回归测试
-
-每次做完导入或删除,你都可以用这条命令快速验证检索效果:
-
-```bash
-.\.venv\Scripts\python.exe scripts/test_lpmm_retrieval.py
-```
-
-它会:
-
-- 初始化 LPMM(加载当前向量库和知识图);
-- 用几条预设问题(包括与 LPMM 和配置相关的问题)进行检索;
-- 打印检索结果以及命中关键词情况。
-
-通过对比不同时间点的输出,你可以判断:
-
-- 某些知识是否已经被成功删除(不再出现在回答中);
-
-- 新增的知识是否已经能被检索到。
-
-### 4.4 进阶:一键刷新(可选)
-
-- 想简单确认“现在这份 data/embedding + data/rag 是否健康”?执行:
-
- `.\.venv\Scripts\python.exe scripts/refresh_lpmm_knowledge.py `
-
- 它会尝试初始化 LPMM,并打印当前段落/实体/关系条数和图大小。
-
-
-
-
-
----
-
-## 五、常见提示与注意事项
-
-1. **看到“网络错误(可重试)”需要担心吗?**
-
- - 不需要。
- - 这些日志说明脚本在自动处理网络抖动,多数情况下会在重试后成功返回结果。
- - 只要脚本最后没有报“重试耗尽并退出”,一般导入/提取结果是有效的。
-
-2. **删除操作会不会“一删全没”?**
-
- - 不会直接“一删全没”:
- - 每次删除会打印摘要信息;
- - 必须输入 `YES` 才会真正执行;
- - 大批次时还有 `--max-delete-nodes` 保护,超过阈值会警告。
- - 但仍然建议:
- - 在大规模删除前备份 `data/embedding` 和 `data/rag`;
- - 先通过 `--dry-run` 看看待删列表。
-
-3. **可以多次导入吗?需要先清空吗?**
-
- - 可以多次导入,系统会根据段落内容的哈希做去重;
- - 不需要每次都清空,只要你希望老数据仍然保留即可;
- - 如果你确实想“重来一遍”,可以:
- - 先备份,然后删除 `data/embedding` 和 `data/rag`;
- - 再重新跑导入流程。
-
-4. **LPMM 开关在哪里?**
-
- - 配置文件:`config/bot_config.toml`;
- - 小节:`[lpmm_knowledge]`;
- - 其中有 `enable = true/false` 开关:
- - 为 `true`:LPMM 知识库启用,问答时会使用;
- - 为 `false`:LPMM 关闭,即使知识库有数据,也不会参与回答。
- - 修改后需要重启主程序,让设置生效。
-
----
-
-如果你是普通用户,只需要记住一句话:
-
-> “导入三步走:预处理 → 信息抽取 → 导入 OpenIE;
-> 删除三步走:先检查 → 再删除 → 然后再检查。”
-
-照着本指南中的命令一步一步执行,就可以安全地管理你的 LPMM 知识库。***
diff --git a/docs-src/plugins/action-components.md b/docs-src/plugins/action-components.md
deleted file mode 100644
index b7d3d6bd..00000000
--- a/docs-src/plugins/action-components.md
+++ /dev/null
@@ -1,271 +0,0 @@
-# ⚡ Action组件详解
-
-## 📖 什么是Action
-
-Action是给麦麦在回复之外提供额外功能的智能组件,**由麦麦的决策系统自主选择是否使用**,具有随机性和拟人化的调用特点。Action不是直接响应用户命令,而是让麦麦根据聊天情境智能地选择合适的动作,使其行为更加自然和真实。
-
-### Action的特点
-
-- 🧠 **智能激活**:麦麦根据多种条件智能判断是否使用
-- 🎲 **可随机性**:可以使用随机数激活,增加行为的不可预测性,更接近真人交流
-- 🤖 **拟人化**:让麦麦的回应更自然、更有个性
-- 🔄 **情境感知**:基于聊天上下文做出合适的反应
-
----
-
-## 🎯 Action组件的基本结构
-首先,所有的Action都应该继承`BaseAction`类。
-
-其次,每个Action组件都应该实现以下基本信息:
-```python
-class ExampleAction(BaseAction):
- action_name = "example_action" # 动作的唯一标识符
- action_description = "这是一个示例动作" # 动作描述
- activation_type = ActionActivationType.ALWAYS # 这里以 ALWAYS 为例
- associated_types = ["text", "emoji", ...] # 关联类型
- parallel_action = False # 是否允许与其他Action并行执行
- action_parameters = {"param1": "参数1的说明", "param2": "参数2的说明", ...}
- # Action使用场景描述 - 帮助LLM判断何时"选择"使用
- action_require = ["使用场景描述1", "使用场景描述2", ...]
-
- async def execute(self) -> Tuple[bool, str]:
- """
- 执行Action的主要逻辑
-
- Returns:
- Tuple[bool, str]: (是否成功, 执行结果描述)
- """
- # ---- 执行动作的逻辑 ----
- return True, "执行成功"
-```
-#### associated_types: 该Action会发送的消息类型,例如文本、表情等。
-
-这部分由Adapter传递给处理器。
-
-以 MaiBot-Napcat-Adapter 为例,可选项目如下:
-| 类型 | 说明 | 格式 |
-| --- | --- | --- |
-| text | 文本消息 | str |
-| emoji | 表情消息 | str: 表情包的无头base64|
-| image | 图片消息 | str: 图片的无头base64 |
-| reply | 回复消息 | str: 回复的消息ID |
-| voice | 语音消息 | str: wav格式语音的无头base64 |
-| command | 命令消息 | 参见Adapter文档 |
-| voiceurl | 语音URL消息 | str: wav格式语音的URL |
-| music | 音乐消息 | str: 这首歌在网易云音乐的音乐id |
-| videourl | 视频URL消息 | str: 视频的URL |
-| file | 文件消息 | str: 文件的路径 |
-
-**请知悉,对于不同的处理器,其支持的消息类型可能会有所不同。在开发时请注意。**
-
-#### action_parameters: 该Action的参数说明。
-这是一个字典,键为参数名,值为参数说明。这个字段可以帮助LLM理解如何使用这个Action,并由LLM返回对应的参数,最后传递到 Action 的 **`action_data`** 属性中。其格式与你定义的格式完全相同 **(除非LLM哈气了,返回了错误的内容)**。
-
----
-
-## 🎯 Action 调用的决策机制
-
-Action采用**两层决策机制**来优化性能和决策质量:
-
-> 设计目的:在加载许多插件的时候降低LLM决策压力,避免让麦麦在过多的选项中纠结。
-
-**第一层:激活控制(Activation Control)**
-
-激活决定麦麦是否 **“知道”** 这个Action的存在,即这个Action是否进入决策候选池。不被激活的Action麦麦永远不会选择。
-
-**第二层:使用决策(Usage Decision)**
-
-在Action被激活后,使用条件决定麦麦什么时候会 **“选择”** 使用这个Action。
-
-### 决策参数详解 🔧
-
-#### 第一层:ActivationType 激活类型说明
-
-| 激活类型 | 说明 | 使用场景 |
-| ----------- | ---------------------------------------- | ---------------------- |
-| [`NEVER`](#never-激活) | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
-| [`ALWAYS`](#always-激活) | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、不回复 |
-| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
-| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
-
-#### `NEVER` 激活
-
-`ActionActivationType.NEVER` 会使得 Action 永远不会被激活
-
-```python
-class DisabledAction(BaseAction):
- activation_type = ActionActivationType.NEVER # 永远不激活
-
- async def execute(self) -> Tuple[bool, str]:
- # 这个Action永远不会被执行
- return False, "这个Action被禁用"
-```
-
-#### `ALWAYS` 激活
-
-`ActionActivationType.ALWAYS` 会使得 Action 永远会被激活,即一直在 Action 候选池中
-
-这种激活方式常用于核心功能,如回复或不回复。
-
-```python
-class AlwaysActivatedAction(BaseAction):
- activation_type = ActionActivationType.ALWAYS # 永远激活
-
- async def execute(self) -> Tuple[bool, str]:
- # 执行核心功能
- return True, "执行了核心功能"
-```
-
-#### `RANDOM` 激活
-
-`ActionActivationType.RANDOM`会使得这个 Action 根据随机概率决定是否加入候选池。
-
-概率则由代码中的`random_activation_probability`控制。在内部实现中我们使用了`random.random()`来生成一个0到1之间的随机数,并与这个概率进行比较。
-
-因此使用这个方法需要实现`random_activation_probability`属性。
-
-```python
-class SurpriseAction(BaseAction):
- activation_type = ActionActivationType.RANDOM # 基于随机概率激活
- # 随机激活概率
- random_activation_probability = 0.1 # 10%概率激活
-
- async def execute(self) -> Tuple[bool, str]:
- # 执行惊喜动作
- return True, "发送了惊喜内容"
-```
-
-#### `KEYWORD` 激活
-
-`ActionActivationType.KEYWORD`会使得这个 Action 在检测到特定关键词时激活。
-
-关键词由代码中的`activation_keywords`定义,而`keyword_case_sensitive`则控制关键词匹配时是否区分大小写。在内部实现中,我们使用了`in`操作符来检查消息内容是否包含这些关键词。
-
-因此,使用此种方法需要实现`activation_keywords`和`keyword_case_sensitive`属性。
-
-```python
-class GreetingAction(BaseAction):
- activation_type = ActionActivationType.KEYWORD # 关键词激活
- activation_keywords = ["你好", "hello", "hi", "嗨"] # 关键词配置
- keyword_case_sensitive = False # 不区分大小写
-
- async def execute(self) -> Tuple[bool, str]:
- # 执行问候逻辑
- return True, "发送了问候"
-```
-
-一个完整的使用`ActionActivationType.KEYWORD`的例子请参考`plugins/hello_world_plugin`中的`ByeAction`。
-
-#### 第二层:使用决策
-
-**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
-
-这一层由以下因素综合决定:
-
-- `action_require`:使用场景描述,帮助LLM判断何时选择
-- `action_parameters`:所需参数,影响Action的可执行性
-- 当前聊天上下文和麦麦的决策逻辑
-
----
-
-### 决策流程示例
-
-```python
-class EmojiAction(BaseAction):
- # 第一层:激活控制
- activation_type = ActionActivationType.RANDOM # 随机激活
- random_activation_probability = 0.1 # 10%概率激活
-
- # 第二层:使用决策
- action_require = [
- "表达情绪时可以选择使用",
- "增加聊天趣味性",
- "不要连续发送多个表情"
- ]
-```
-
-**决策流程**:
-
-1. **第一层激活判断**:
-
- - 使用随机数进行决策,当`random.random() < self.random_activation_probability`时,麦麦才"知道"可以使用这个Action
-2. **第二层使用决策**:
-
- - 即使Action被激活,麦麦还会根据 `action_require` 中的条件判断是否真正选择使用
- - 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
-
----
-
-## Action 内置属性说明
-```python
-class BaseAction:
- def __init__(self):
- # 消息相关属性
- self.log_prefix: str # 日志前缀
- self.group_id: str # 群组ID
- self.group_name: str # 群组名称
- self.user_id: str # 用户ID
- self.user_nickname: str # 用户昵称
- self.platform: str # 平台类型 (qq, telegram等)
- self.chat_id: str # 聊天ID
- self.chat_stream: ChatStream # 聊天流对象
- self.is_group: bool # 是否群聊
-
- # 消息体
- self.action_message: dict # 消息数据
-
- # Action相关属性
- self.action_data: dict # Action执行时的数据
- self.thinking_id: str # 思考ID
-```
-action_message为一个字典,包含的键值对如下(省略了不必要的键值对)
-
-```python
-{
- "message_id": "1234567890", # 消息id,str
- "time": 1627545600.0, # 时间戳,float
- "chat_id": "abcdef123456", # 聊天ID,str
- "reply_to": None, # 回复消息id,str或None
- "interest_value": 0.85, # 兴趣值,float
- "is_mentioned": True, # 是否被提及,bool
- "chat_info_last_active_time": 1627548600.0, # 最后活跃时间,float
- "processed_plain_text": None, # 处理后的文本,str或None
- "additional_config": None, # Adapter传来的additional_config,dict或None
- "is_emoji": False, # 是否为表情,bool
- "is_picid": False, # 是否为图片ID,bool
- "is_command": False # 是否为命令,bool
-}
-```
-
-部分值的格式请自行查询数据库。
-
----
-
-## Action 内置方法说明
-```python
-class BaseAction:
- def get_config(self, key: str, default=None):
- """获取插件配置值,使用嵌套键访问"""
-
- async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]:
- """等待新消息或超时"""
-
- async def send_text(self, content: str, reply_to: str = "", reply_to_platform_id: str = "", typing: bool = False) -> bool:
- """发送文本消息"""
-
- async def send_emoji(self, emoji_base64: str) -> bool:
- """发送表情包"""
-
- async def send_image(self, image_base64: str) -> bool:
- """发送图片"""
-
- async def send_custom(self, message_type: str, content: str, typing: bool = False, reply_to: str = "") -> bool:
- """发送自定义类型消息"""
-
- async def store_action_info(self, action_build_into_prompt: bool = False, action_prompt_display: str = "", action_done: bool = True) -> None:
- """存储动作信息到数据库"""
-
- async def send_command(self, command_name: str, args: Optional[dict] = None, display_message: str = "", storage_message: bool = True) -> bool:
- """发送命令消息"""
-```
-具体参数与用法参见`BaseAction`基类的定义。
\ No newline at end of file
diff --git a/docs-src/plugins/api/chat-api.md b/docs-src/plugins/api/chat-api.md
deleted file mode 100644
index b9b95e27..00000000
--- a/docs-src/plugins/api/chat-api.md
+++ /dev/null
@@ -1,130 +0,0 @@
-# 聊天API
-
-聊天API模块专门负责聊天信息的查询和管理,帮助插件获取和管理不同的聊天流。
-
-## 导入方式
-
-```python
-from src.plugin_system import chat_api
-# 或者
-from src.plugin_system.apis import chat_api
-```
-
-一种**Deprecated**方式:
-```python
-from src.plugin_system.apis.chat_api import ChatManager
-```
-
-## 主要功能
-
-### 1. 获取所有的聊天流
-
-```python
-def get_all_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
-```
-
-**Args**:
-- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的聊天流。
-
-**Returns**:
-- `List[ChatStream]`:聊天流列表
-
-### 2. 获取群聊聊天流
-
-```python
-def get_group_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
-```
-
-**Args**:
-- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的群聊流。
-
-**Returns**:
-- `List[ChatStream]`:群聊聊天流列表
-
-### 3. 获取私聊聊天流
-
-```python
-def get_private_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
-```
-
-**Args**:
-- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的私聊流。
-
-**Returns**:
-- `List[ChatStream]`:私聊聊天流列表
-
-### 4. 根据群ID获取聊天流
-
-```python
-def get_stream_by_group_id(group_id: str, platform: Optional[str] | SpecialTypes = "qq") -> Optional[ChatStream]:
-```
-
-**Args**:
-- `group_id`:群聊ID
-- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的群聊流。
-
-**Returns**:
-- `Optional[ChatStream]`:聊天流对象,如果未找到返回None
-
-### 5. 根据用户ID获取私聊流
-
-```python
-def get_stream_by_user_id(user_id: str, platform: Optional[str] | SpecialTypes = "qq") -> Optional[ChatStream]:
-```
-
-**Args**:
-- `user_id`:用户ID
-- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的私聊流。
-
-**Returns**:
-- `Optional[ChatStream]`:聊天流对象,如果未找到返回None
-
-### 6. 获取聊天流类型
-
-```python
-def get_stream_type(chat_stream: ChatStream) -> str:
-```
-
-**Args**:
-- `chat_stream`:聊天流对象
-
-**Returns**:
-- `str`:聊天流类型,可能的值包括`private`(私聊流),`group`(群聊流)以及`unknown`(未知类型)。
-
-### 7. 获取聊天流信息
-
-```python
-def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
-```
-
-**Args**:
-- `chat_stream`:聊天流对象
-
-**Returns**:
-- `Dict[str, Any]`:聊天流的详细信息,包括但不限于:
- - `stream_id`:聊天流ID
- - `platform`:平台名称
- - `type`:聊天流类型
- - `group_id`:群聊ID
- - `group_name`:群聊名称
- - `user_id`:用户ID
- - `user_name`:用户名称
-
-### 8. 获取聊天流统计摘要
-
-```python
-def get_streams_summary() -> Dict[str, int]:
-```
-
-**Returns**:
-- `Dict[str, int]`:聊天流统计信息摘要,包含以下键:
- - `total_streams`:总聊天流数量
- - `group_streams`:群聊流数量
- - `private_streams`:私聊流数量
- - `qq_streams`:QQ平台流数量
-
-
-## 注意事项
-
-1. 大部分函数在参数不合法时候会抛出异常,请确保你的程序进行了捕获。
-2. `ChatStream`对象包含了聊天的完整信息,包括用户信息、群信息等。
\ No newline at end of file
diff --git a/docs-src/plugins/api/component-manage-api.md b/docs-src/plugins/api/component-manage-api.md
deleted file mode 100644
index a857fb27..00000000
--- a/docs-src/plugins/api/component-manage-api.md
+++ /dev/null
@@ -1,194 +0,0 @@
-# 组件管理API
-
-组件管理API模块提供了对插件组件的查询和管理功能,使得插件能够获取和使用组件相关的信息。
-
-## 导入方式
-```python
-from src.plugin_system.apis import component_manage_api
-# 或者
-from src.plugin_system import component_manage_api
-```
-
-## 功能概述
-
-组件管理API主要提供以下功能:
-- **插件信息查询** - 获取所有插件或指定插件的信息。
-- **组件查询** - 按名称或类型查询组件信息。
-- **组件管理** - 启用或禁用组件,支持全局和局部操作。
-
-## 主要功能
-
-### 1. 获取所有插件信息
-```python
-def get_all_plugin_info() -> Dict[str, PluginInfo]:
-```
-获取所有插件的信息。
-
-**Returns:**
-- `Dict[str, PluginInfo]` - 包含所有插件信息的字典,键为插件名称,值为 `PluginInfo` 对象。
-
-### 2. 获取指定插件信息
-```python
-def get_plugin_info(plugin_name: str) -> Optional[PluginInfo]:
-```
-获取指定插件的信息。
-
-**Args:**
-- `plugin_name` (str): 插件名称。
-
-**Returns:**
-- `Optional[PluginInfo]`: 插件信息对象,如果插件不存在则返回 `None`。
-
-### 3. 获取指定组件信息
-```python
-def get_component_info(component_name: str, component_type: ComponentType) -> Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
-```
-获取指定组件的信息。
-
-**Args:**
-- `component_name` (str): 组件名称。
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 组件信息对象,如果组件不存在则返回 `None`。
-
-### 4. 获取指定类型的所有组件信息
-```python
-def get_components_info_by_type(component_type: ComponentType) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
-```
-获取指定类型的所有组件信息。
-
-**Args:**
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 包含指定类型组件信息的字典,键为组件名称,值为对应的组件信息对象。
-
-### 5. 获取指定类型的所有启用的组件信息
-```python
-def get_enabled_components_info_by_type(component_type: ComponentType) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
-```
-获取指定类型的所有启用的组件信息。
-
-**Args:**
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 包含指定类型启用组件信息的字典,键为组件名称,值为对应的组件信息对象。
-
-### 6. 获取指定 Action 的注册信息
-```python
-def get_registered_action_info(action_name: str) -> Optional[ActionInfo]:
-```
-获取指定 Action 的注册信息。
-
-**Args:**
-- `action_name` (str): Action 名称。
-
-**Returns:**
-- `Optional[ActionInfo]` - Action 信息对象,如果 Action 不存在则返回 `None`。
-
-### 7. 获取指定 Command 的注册信息
-```python
-def get_registered_command_info(command_name: str) -> Optional[CommandInfo]:
-```
-获取指定 Command 的注册信息。
-
-**Args:**
-- `command_name` (str): Command 名称。
-
-**Returns:**
-- `Optional[CommandInfo]` - Command 信息对象,如果 Command 不存在则返回 `None`。
-
-### 8. 获取指定 Tool 的注册信息
-```python
-def get_registered_tool_info(tool_name: str) -> Optional[ToolInfo]:
-```
-获取指定 Tool 的注册信息。
-
-**Args:**
-- `tool_name` (str): Tool 名称。
-
-**Returns:**
-- `Optional[ToolInfo]` - Tool 信息对象,如果 Tool 不存在则返回 `None`。
-
-### 9. 获取指定 EventHandler 的注册信息
-```python
-def get_registered_event_handler_info(event_handler_name: str) -> Optional[EventHandlerInfo]:
-```
-获取指定 EventHandler 的注册信息。
-
-**Args:**
-- `event_handler_name` (str): EventHandler 名称。
-
-**Returns:**
-- `Optional[EventHandlerInfo]` - EventHandler 信息对象,如果 EventHandler 不存在则返回 `None`。
-
-### 10. 全局启用指定组件
-```python
-def globally_enable_component(component_name: str, component_type: ComponentType) -> bool:
-```
-全局启用指定组件。
-
-**Args:**
-- `component_name` (str): 组件名称。
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `bool` - 启用成功返回 `True`,否则返回 `False`。
-
-### 11. 全局禁用指定组件
-```python
-async def globally_disable_component(component_name: str, component_type: ComponentType) -> bool:
-```
-全局禁用指定组件。
-
-**此函数是异步的,确保在异步环境中调用。**
-
-**Args:**
-- `component_name` (str): 组件名称。
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `bool` - 禁用成功返回 `True`,否则返回 `False`。
-
-### 12. 局部启用指定组件
-```python
-def locally_enable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
-```
-局部启用指定组件。
-
-**Args:**
-- `component_name` (str): 组件名称。
-- `component_type` (ComponentType): 组件类型。
-- `stream_id` (str): 消息流 ID。
-
-**Returns:**
-- `bool` - 启用成功返回 `True`,否则返回 `False`。
-
-### 13. 局部禁用指定组件
-```python
-def locally_disable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
-```
-局部禁用指定组件。
-
-**Args:**
-- `component_name` (str): 组件名称。
-- `component_type` (ComponentType): 组件类型。
-- `stream_id` (str): 消息流 ID。
-
-**Returns:**
-- `bool` - 禁用成功返回 `True`,否则返回 `False`。
-
-### 14. 获取指定消息流中禁用的组件列表
-```python
-def get_locally_disabled_components(stream_id: str, component_type: ComponentType) -> list[str]:
-```
-获取指定消息流中禁用的组件列表。
-
-**Args:**
-- `stream_id` (str): 消息流 ID。
-- `component_type` (ComponentType): 组件类型。
-
-**Returns:**
-- `list[str]` - 禁用的组件名称列表。
diff --git a/docs-src/plugins/api/config-api.md b/docs-src/plugins/api/config-api.md
deleted file mode 100644
index 2ee1cdfc..00000000
--- a/docs-src/plugins/api/config-api.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# 配置API
-
-配置API模块提供了配置读取功能,让插件能够安全地访问全局配置和插件配置。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import config_api
-# 或者
-from src.plugin_system import config_api
-```
-
-## 主要功能
-
-### 1. 访问全局配置
-
-```python
-def get_global_config(key: str, default: Any = None) -> Any:
-```
-
-**Args**:
-- `key`: 命名空间式配置键名,使用嵌套访问,如 "section.subsection.key",大小写敏感
-- `default`: 如果配置不存在时返回的默认值
-
-**Returns**:
-- `Any`: 配置值或默认值
-
-#### 示例:
-获取机器人昵称
-```python
-bot_name = config_api.get_global_config("bot.nickname", "MaiBot")
-```
-
-### 2. 获取插件配置
-
-```python
-def get_plugin_config(plugin_config: dict, key: str, default: Any = None) -> Any:
-```
-**Args**:
-- `plugin_config`: 插件配置字典
-- `key`: 配置键名,支持嵌套访问如 "section.subsection.key",大小写敏感
-- `default`: 如果配置不存在时返回的默认值
-
-**Returns**:
-- `Any`: 配置值或默认值
-
-## 注意事项
-
-1. **只读访问**:配置API只提供读取功能,插件不能修改全局配置
-2. **错误处理**:所有函数都有错误处理,失败时会记录日志并返回默认值
-3. **安全性**:插件通过此API访问配置是安全和隔离的
-4. **性能**:频繁访问的配置建议在插件初始化时获取并缓存
\ No newline at end of file
diff --git a/docs-src/plugins/api/database-api.md b/docs-src/plugins/api/database-api.md
deleted file mode 100644
index 5b6b4468..00000000
--- a/docs-src/plugins/api/database-api.md
+++ /dev/null
@@ -1,216 +0,0 @@
-# 数据库API
-
-数据库API模块提供通用的数据库操作功能,支持查询、创建、更新和删除记录,采用Peewee ORM模型。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import database_api
-# 或者
-from src.plugin_system import database_api
-```
-
-## 主要功能
-
-### 1. 通用数据库操作
-
-```python
-async def db_query(
- model_class: Type[Model],
- data: Optional[Dict[str, Any]] = None,
- query_type: Optional[str] = "get",
- filters: Optional[Dict[str, Any]] = None,
- limit: Optional[int] = None,
- order_by: Optional[List[str]] = None,
- single_result: Optional[bool] = False,
-) -> Union[List[Dict[str, Any]], Dict[str, Any], None]:
-```
-执行数据库查询操作的通用接口。
-
-**Args:**
-- `model_class`: Peewee模型类。
- - Peewee模型类可以在`src.common.database.database_model`模块中找到,如`ActionRecords`、`Messages`等。
-- `data`: 用于创建或更新的数据
-- `query_type`: 查询类型
- - 可选值: `get`, `create`, `update`, `delete`, `count`。
-- `filters`: 过滤条件字典,键为字段名,值为要匹配的值。
-- `limit`: 限制结果数量。
-- `order_by`: 排序字段列表,使用字段名,前缀'-'表示降序。
- - 排序字段,前缀`-`表示降序,例如`-time`表示按时间字段(即`time`字段)降序
-- `single_result`: 是否只返回单个结果。
-
-**Returns:**
-- 根据查询类型返回不同的结果:
- - `get`: 返回查询结果列表或单个结果。(如果 `single_result=True`)
- - `create`: 返回创建的记录。
- - `update`: 返回受影响的行数。
- - `delete`: 返回受影响的行数。
- - `count`: 返回记录数量。
-
-#### 示例
-
-1. 查询最近10条消息
-```python
-messages = await database_api.db_query(
- Messages,
- query_type="get",
- filters={"chat_id": chat_stream.stream_id},
- limit=10,
- order_by=["-time"]
-)
-```
-2. 创建一条记录
-```python
-new_record = await database_api.db_query(
- ActionRecords,
- data={"action_id": "123", "time": time.time(), "action_name": "TestAction"},
- query_type="create",
-)
-```
-3. 更新记录
-```python
-updated_count = await database_api.db_query(
- ActionRecords,
- data={"action_done": True},
- query_type="update",
- filters={"action_id": "123"},
-)
-```
-4. 删除记录
-```python
-deleted_count = await database_api.db_query(
- ActionRecords,
- query_type="delete",
- filters={"action_id": "123"}
-)
-```
-5. 计数
-```python
-count = await database_api.db_query(
- Messages,
- query_type="count",
- filters={"chat_id": chat_stream.stream_id}
-)
-```
-
-### 2. 数据库保存
-```python
-async def db_save(
- model_class: Type[Model], data: Dict[str, Any], key_field: Optional[str] = None, key_value: Optional[Any] = None
-) -> Optional[Dict[str, Any]]:
-```
-保存数据到数据库(创建或更新)
-
-如果提供了key_field和key_value,会先尝试查找匹配的记录进行更新;
-
-如果没有找到匹配记录,或未提供key_field和key_value,则创建新记录。
-
-**Args:**
-- `model_class`: Peewee模型类。
-- `data`: 要保存的数据字典。
-- `key_field`: 用于查找现有记录的字段名,例如"action_id"。
-- `key_value`: 用于查找现有记录的字段值。
-
-**Returns:**
-- `Optional[Dict[str, Any]]`: 保存后的记录数据,失败时返回None。
-
-#### 示例
-创建或更新一条记录
-```python
-record = await database_api.db_save(
- ActionRecords,
- {
- "action_id": "123",
- "time": time.time(),
- "action_name": "TestAction",
- "action_done": True
- },
- key_field="action_id",
- key_value="123"
-)
-```
-
-### 3. 数据库获取
-```python
-async def db_get(
- model_class: Type[Model],
- filters: Optional[Dict[str, Any]] = None,
- limit: Optional[int] = None,
- order_by: Optional[str] = None,
- single_result: Optional[bool] = False,
-) -> Union[List[Dict[str, Any]], Dict[str, Any], None]:
-```
-
-从数据库获取记录
-
-这是db_query方法的简化版本,专注于数据检索操作。
-
-**Args:**
-- `model_class`: Peewee模型类。
-- `filters`: 过滤条件字典,键为字段名,值为要匹配的值。
-- `limit`: 限制结果数量。
-- `order_by`: 排序字段,使用字段名,前缀'-'表示降序。
-- `single_result`: 是否只返回单个结果,如果为True,则返回单个记录字典或None;否则返回记录字典列表或空列表
-
-**Returns:**
-- `Union[List[Dict], Dict, None]`: 查询结果列表或单个结果(如果`single_result=True`),失败时返回None。
-
-#### 示例
-1. 获取单个记录
-```python
-record = await database_api.db_get(
- ActionRecords,
- filters={"action_id": "123"},
- limit=1
-)
-```
-2. 获取最近10条记录
-```python
-records = await database_api.db_get(
- Messages,
- filters={"chat_id": chat_stream.stream_id},
- limit=10,
- order_by="-time",
-)
-```
-
-### 4. 动作信息存储
-```python
-async def store_action_info(
- chat_stream=None,
- action_build_into_prompt: bool = False,
- action_prompt_display: str = "",
- action_done: bool = True,
- thinking_id: str = "",
- action_data: Optional[dict] = None,
- action_name: str = "",
-) -> Optional[Dict[str, Any]]:
-```
-存储动作信息到数据库,是一种针对 Action 的 `db_save()` 的封装函数。
-
-将Action执行的相关信息保存到ActionRecords表中,用于后续的记忆和上下文构建。
-
-**Args:**
-- `chat_stream`: 聊天流对象,包含聊天ID等信息。
-- `action_build_into_prompt`: 是否将动作信息构建到提示中。
-- `action_prompt_display`: 动作提示的显示文本。
-- `action_done`: 动作是否完成。
-- `thinking_id`: 思考过程的ID。
-- `action_data`: 动作的数据字典。
-- `action_name`: 动作的名称。
-
-**Returns:**
-- `Optional[Dict[str, Any]]`: 存储后的记录数据,失败时返回None。
-
-#### 示例
-```python
-record = await database_api.store_action_info(
- chat_stream=chat_stream,
- action_build_into_prompt=True,
- action_prompt_display="执行了回复动作",
- action_done=True,
- thinking_id="thinking_123",
- action_data={"content": "Hello"},
- action_name="reply_action"
-)
-```
\ No newline at end of file
diff --git a/docs-src/plugins/api/emoji-api.md b/docs-src/plugins/api/emoji-api.md
deleted file mode 100644
index ce9dd0c8..00000000
--- a/docs-src/plugins/api/emoji-api.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# 表情包API
-
-表情包API模块提供表情包的获取、查询和管理功能,让插件能够智能地选择和使用表情包。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import emoji_api
-# 或者
-from src.plugin_system import emoji_api
-```
-
-## 二步走识别优化
-
-从新版本开始,表情包识别系统采用了**二步走识别 + 智能缓存**的优化方案:
-
-### **收到表情包时的识别流程**
-1. **第一步**:VLM视觉分析 - 生成详细描述
-2. **第二步**:LLM情感分析 - 基于详细描述提取核心情感标签
-3. **缓存机制**:将情感标签缓存到数据库,详细描述保存到Images表
-
-### **注册表情包时的优化**
-- **智能复用**:优先从Images表获取已有的详细描述
-- **避免重复**:如果表情包之前被收到过,跳过VLM调用
-- **性能提升**:减少不必要的AI调用,降低延时和成本
-
-### **缓存策略**
-- **ImageDescriptions表**:缓存最终的情感标签(用于快速显示)
-- **Images表**:保存详细描述(用于注册时复用)
-- **双重检查**:防止并发情况下的重复生成
-
-## 主要功能
-
-### 1. 表情包获取
-```python
-async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]:
-```
-根据场景描述选择表情包
-
-**Args:**
-- `description`:表情包的描述文本,例如"开心"、"难过"、"愤怒"等
-
-**Returns:**
-- `Optional[Tuple[str, str, str]]`:一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到匹配的表情包则返回None
-
-#### 示例
-```python
-emoji_result = await emoji_api.get_by_description("大笑")
-if emoji_result:
- emoji_base64, description, matched_scene = emoji_result
- print(f"获取到表情包: {description}, 场景: {matched_scene}")
- # 可以将emoji_base64用于发送表情包
-```
-
-### 2. 随机获取表情包
-```python
-async def get_random(count: Optional[int] = 1) -> List[Tuple[str, str, str]]:
-```
-随机获取指定数量的表情包
-
-**Args:**
-- `count`:要获取的表情包数量,默认为1
-
-**Returns:**
-- `List[Tuple[str, str, str]]`:一个包含多个表情包的列表,每个元素是一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到或出错则返回空列表
-
-### 3. 根据情感获取表情包
-```python
-async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
-```
-根据情感标签获取表情包
-
-**Args:**
-- `emotion`:情感标签,例如"开心"、"悲伤"、"愤怒"等
-
-**Returns:**
-- `Optional[Tuple[str, str, str]]`:一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到则返回None
-
-### 4. 获取表情包数量
-```python
-def get_count() -> int:
-```
-获取当前可用表情包的数量
-
-### 5. 获取表情包系统信息
-```python
-def get_info() -> Dict[str, Any]:
-```
-获取表情包系统的基本信息
-
-**Returns:**
-- `Dict[str, Any]`:包含表情包数量、描述等信息的字典,包含以下键:
- - `current_count`:当前表情包数量
- - `max_count`:最大表情包数量
- - `available_emojis`:当前可用的表情包数量
-
-### 6. 获取所有可用的情感标签
-```python
-def get_emotions() -> List[str]:
-```
-获取所有可用的情感标签 **(已经去重)**
-
-### 7. 获取所有表情包描述
-```python
-def get_descriptions() -> List[str]:
-```
-获取所有表情包的描述列表
-
-## 场景描述说明
-
-### 常用场景描述
-表情包系统支持多种具体的场景描述,举例如下:
-
-- **开心类场景**:开心的大笑、满意的微笑、兴奋的手舞足蹈
-- **无奈类场景**:表示无奈和沮丧、轻微的讽刺、无语的摇头
-- **愤怒类场景**:愤怒和不满、生气的瞪视、暴躁的抓狂
-- **惊讶类场景**:震惊的表情、意外的发现、困惑的思考
-- **可爱类场景**:卖萌的表情、撒娇的动作、害羞的样子
-
-### 情感关键词示例
-系统支持的情感关键词举例如下:
-- 大笑、微笑、兴奋、手舞足蹈
-- 无奈、沮丧、讽刺、无语、摇头
-- 愤怒、不满、生气、瞪视、抓狂
-- 震惊、意外、困惑、思考
-- 卖萌、撒娇、害羞、可爱
-
-### 匹配机制
-- **精确匹配**:优先匹配完整的场景描述,如"开心的大笑"
-- **关键词匹配**:如果没有精确匹配,则根据关键词进行模糊匹配
-- **语义匹配**:系统会理解场景的语义含义进行智能匹配
-
-## 注意事项
-
-1. **异步函数**:部分函数是异步的,需要使用 `await`
-2. **返回格式**:表情包以base64编码返回,可直接用于发送
-3. **错误处理**:所有函数都有错误处理,失败时返回None,空列表或默认值
-4. **使用统计**:系统会记录表情包的使用次数
-5. **文件依赖**:表情包依赖于本地文件,确保表情包文件存在
-6. **编码格式**:返回的是base64编码的图片数据,可直接用于网络传输
-7. **场景理解**:系统能理解具体的场景描述,比简单的情感分类更准确
diff --git a/docs-src/plugins/api/generator-api.md b/docs-src/plugins/api/generator-api.md
deleted file mode 100644
index e0ea28cb..00000000
--- a/docs-src/plugins/api/generator-api.md
+++ /dev/null
@@ -1,198 +0,0 @@
-# 回复生成器API
-
-回复生成器API模块提供智能回复生成功能,让插件能够使用系统的回复生成器来产生自然的聊天回复。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import generator_api
-# 或者
-from src.plugin_system import generator_api
-```
-
-## 主要功能
-
-### 1. 回复器获取
-```python
-def get_replyer(
- chat_stream: Optional[ChatStream] = None,
- chat_id: Optional[str] = None,
- model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
- request_type: str = "replyer",
-) -> Optional[DefaultReplyer]:
-```
-获取回复器对象
-
-优先使用chat_stream,如果没有则使用chat_id直接查找。
-
-使用 ReplyerManager 来管理实例,避免重复创建。
-
-**Args:**
-- `chat_stream`: 聊天流对象
-- `chat_id`: 聊天ID(实际上就是`stream_id`)
-- `model_set_with_weight`: 模型配置列表,每个元素为 `(TaskConfig, weight)` 元组
-- `request_type`: 请求类型,用于记录LLM使用情况,可以不写
-
-**Returns:**
-- `DefaultReplyer`: 回复器对象,如果获取失败则返回None
-
-#### 示例
-```python
-# 使用聊天流获取回复器
-replyer = generator_api.get_replyer(chat_stream=chat_stream)
-
-# 使用平台和ID获取回复器
-replyer = generator_api.get_replyer(chat_id="123456789")
-```
-
-### 2. 回复生成
-```python
-async def generate_reply(
- chat_stream: Optional[ChatStream] = None,
- chat_id: Optional[str] = None,
- action_data: Optional[Dict[str, Any]] = None,
- reply_to: str = "",
- extra_info: str = "",
- available_actions: Optional[Dict[str, ActionInfo]] = None,
- enable_splitter: bool = True,
- enable_chinese_typo: bool = True,
- return_prompt: bool = False,
- model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
- request_type: str = "generator_api",
-) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
-```
-生成回复
-
-优先使用chat_stream,如果没有则使用chat_id直接查找。
-
-**Args:**
-- `chat_stream`: 聊天流对象
-- `chat_id`: 聊天ID(实际上就是`stream_id`)
-- `action_data`: 动作数据(向下兼容,包含`reply_to`和`extra_info`)
-- `reply_to`: 回复目标,格式为 `{发送者的person_name:消息内容}`
-- `extra_info`: 附加信息
-- `available_actions`: 可用动作字典,格式为 `{"action_name": ActionInfo}`
-- `enable_splitter`: 是否启用分割器
-- `enable_chinese_typo`: 是否启用中文错别字
-- `return_prompt`: 是否返回提示词
-- `model_set_with_weight`: 模型配置列表,每个元素为 `(TaskConfig, weight)` 元组
-- `request_type`: 请求类型(可选,记录LLM使用)
-- `request_type`: 请求类型,用于记录LLM使用情况
-
-**Returns:**
-- `Tuple[bool, List[Tuple[str, Any]], Optional[str]]`: (是否成功, 回复集合, 提示词)
-
-#### 示例
-```python
-success, reply_set, prompt = await generator_api.generate_reply(
- chat_stream=chat_stream,
- action_data=action_data,
- reply_to="麦麦:你好",
- available_actions=action_info,
- return_prompt=True
-)
-if success:
- for reply_type, reply_content in reply_set:
- print(f"回复类型: {reply_type}, 内容: {reply_content}")
- if prompt:
- print(f"使用的提示词: {prompt}")
-```
-
-### 3. 回复重写
-```python
-async def rewrite_reply(
- chat_stream: Optional[ChatStream] = None,
- reply_data: Optional[Dict[str, Any]] = None,
- chat_id: Optional[str] = None,
- enable_splitter: bool = True,
- enable_chinese_typo: bool = True,
- model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
- raw_reply: str = "",
- reason: str = "",
- reply_to: str = "",
- return_prompt: bool = False,
-) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
-```
-重写回复,使用新的内容替换旧的回复内容。
-
-优先使用chat_stream,如果没有则使用chat_id直接查找。
-
-**Args:**
-- `chat_stream`: 聊天流对象
-- `reply_data`: 回复数据,包含`raw_reply`, `reason`和`reply_to`,**(向下兼容备用,当其他参数缺失时从此获取)**
-- `chat_id`: 聊天ID(实际上就是`stream_id`)
-- `enable_splitter`: 是否启用分割器
-- `enable_chinese_typo`: 是否启用中文错别字
-- `model_set_with_weight`: 模型配置列表,每个元素为 (TaskConfig, weight) 元组
-- `raw_reply`: 原始回复内容
-- `reason`: 重写原因
-- `reply_to`: 回复目标,格式为 `{发送者的person_name:消息内容}`
-
-**Returns:**
-- `Tuple[bool, List[Tuple[str, Any]], Optional[str]]`: (是否成功, 回复集合, 提示词)
-
-#### 示例
-```python
-success, reply_set, prompt = await generator_api.rewrite_reply(
- chat_stream=chat_stream,
- raw_reply="原始回复内容",
- reason="重写原因",
- reply_to="麦麦:你好",
- return_prompt=True
-)
-if success:
- for reply_type, reply_content in reply_set:
- print(f"回复类型: {reply_type}, 内容: {reply_content}")
- if prompt:
- print(f"使用的提示词: {prompt}")
-```
-
-## 回复集合`reply_set`格式
-
-### 回复类型
-生成的回复集合包含多种类型的回复:
-
-- `"text"`:纯文本回复
-- `"emoji"`:表情包回复
-- `"image"`:图片回复
-- `"mixed"`:混合类型回复
-
-### 回复集合结构
-```python
-# 示例回复集合
-reply_set = [
- ("text", "很高兴见到你!"),
- ("emoji", "emoji_base64_data"),
- ("text", "有什么可以帮助你的吗?")
-]
-```
-
-### 4. 自定义提示词回复
-```python
-async def generate_response_custom(
- chat_stream: Optional[ChatStream] = None,
- chat_id: Optional[str] = None,
- model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
- prompt: str = "",
-) -> Optional[str]:
-```
-生成自定义提示词回复
-
-优先使用chat_stream,如果没有则使用chat_id直接查找。
-
-**Args:**
-- `chat_stream`: 聊天流对象
-- `chat_id`: 聊天ID(备用)
-- `model_set_with_weight`: 模型集合配置列表
-- `prompt`: 自定义提示词
-
-**Returns:**
-- `Optional[str]`: 生成的自定义回复内容,如果生成失败则返回None
-
-## 注意事项
-
-1. **异步操作**:部分函数是异步的,须使用`await`
-2. **聊天流依赖**:需要有效的聊天流对象才能正常工作
-3. **性能考虑**:回复生成可能需要一些时间,特别是使用LLM时
-4. **回复格式**:返回的回复集合是元组列表,包含类型和内容
-5. **上下文感知**:生成器会考虑聊天上下文和历史消息,除非你用的是自定义提示词。
diff --git a/docs-src/plugins/api/llm-api.md b/docs-src/plugins/api/llm-api.md
deleted file mode 100644
index d35ea68b..00000000
--- a/docs-src/plugins/api/llm-api.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# LLM API
-
-LLM API模块提供与大语言模型交互的功能,让插件能够使用系统配置的LLM模型进行内容生成。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import llm_api
-# 或者
-from src.plugin_system import llm_api
-```
-
-## 主要功能
-
-### 1. 查询可用模型
-```python
-def get_available_models() -> Dict[str, TaskConfig]:
-```
-获取所有可用的模型配置。
-
-**Return:**
-- `Dict[str, TaskConfig]`:模型配置字典,key为模型名称,value为模型配置对象。
-
-### 2. 使用模型生成内容
-```python
-async def generate_with_model(
- prompt: str,
- model_config: TaskConfig,
- request_type: str = "plugin.generate",
- temperature: Optional[float] = None,
- max_tokens: Optional[int] = None,
-) -> Tuple[bool, str, str, str]:
-```
-使用指定模型生成内容。
-
-**Args:**
-- `prompt`:提示词。
-- `model_config`:模型配置对象(从 `get_available_models` 获取)。
-- `request_type`:请求类型标识,默认为 `"plugin.generate"`。
-- `temperature`:生成内容的温度设置,影响输出的随机性。
-- `max_tokens`:生成内容的最大token数。
-
-**Return:**
-- `Tuple[bool, str, str, str]`:返回一个元组,包含(是否成功, 生成的内容, 推理过程, 模型名称)。
-
-### 3. 有Tool情况下使用模型生成内容
-```python
-async def generate_with_model_with_tools(
- prompt: str,
- model_config: TaskConfig,
- tool_options: List[Dict[str, Any]] | None = None,
- request_type: str = "plugin.generate",
- temperature: Optional[float] = None,
- max_tokens: Optional[int] = None,
-) -> Tuple[bool, str, str, str, List[ToolCall] | None]:
-```
-使用指定模型生成内容,并支持工具调用。
-
-**Args:**
-- `prompt`:提示词。
-- `model_config`:模型配置对象(从 `get_available_models` 获取)。
-- `tool_options`:工具选项列表,包含可用工具的配置,字典为每一个工具的定义,参见[tool-components.md](../tool-components.md#属性说明),可用`tool_api.get_llm_available_tool_definitions()`获取并选择。
-- `request_type`:请求类型标识,默认为 `"plugin.generate"`。
-- `temperature`:生成内容的温度设置,影响输出的随机性。
-- `max_tokens`:生成内容的最大token数。
\ No newline at end of file
diff --git a/docs-src/plugins/api/logging-api.md b/docs-src/plugins/api/logging-api.md
deleted file mode 100644
index 5576bf5c..00000000
--- a/docs-src/plugins/api/logging-api.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Logging API
-
-Logging API模块提供了获取本体logger的功能,允许插件记录日志信息。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import get_logger
-# 或者
-from src.plugin_system import get_logger
-```
-
-## 主要功能
-### 1. 获取本体logger
-```python
-def get_logger(name: str) -> structlog.stdlib.BoundLogger:
-```
-获取本体logger实例。
-
-**Args:**
-- `name` (str): 日志记录器的名称。
-
-**Returns:**
-- 一个logger实例,有以下方法:
- - `debug`
- - `info`
- - `warning`
- - `error`
- - `critical`
\ No newline at end of file
diff --git a/docs-src/plugins/api/message-api.md b/docs-src/plugins/api/message-api.md
deleted file mode 100644
index 85d83a9b..00000000
--- a/docs-src/plugins/api/message-api.md
+++ /dev/null
@@ -1,372 +0,0 @@
-# 消息API
-
-消息API提供了强大的消息查询、计数和格式化功能,让你轻松处理聊天消息数据。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import message_api
-# 或者
-from src.plugin_system import message_api
-```
-
-## 功能概述
-
-消息API主要提供三大类功能:
-- **消息查询** - 按时间、聊天、用户等条件查询消息
-- **消息计数** - 统计新消息数量
-- **消息格式化** - 将消息转换为可读格式
-
-## 主要功能
-
-### 1. 按照事件查询消息
-```python
-def get_messages_by_time(
- start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest", filter_mai: bool = False
-) -> List[Dict[str, Any]]:
-```
-获取指定时间范围内的消息。
-
-**Args:**
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-消息列表中包含的键与`Messages`类的属性一致。(位于`src.common.database.database_model`)
-
-### 2. 获取指定聊天中指定时间范围内的信息
-```python
-def get_messages_by_time_in_chat(
- chat_id: str,
- start_time: float,
- end_time: float,
- limit: int = 0,
- limit_mode: str = "latest",
- filter_mai: bool = False,
-) -> List[Dict[str, Any]]:
-```
-获取指定聊天中指定时间范围内的消息。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 3. 获取指定聊天中指定时间范围内的信息(包含边界)
-```python
-def get_messages_by_time_in_chat_inclusive(
- chat_id: str,
- start_time: float,
- end_time: float,
- limit: int = 0,
- limit_mode: str = "latest",
- filter_mai: bool = False,
- filter_command: bool = False,
-) -> List[Dict[str, Any]]:
-```
-获取指定聊天中指定时间范围内的消息(包含边界)。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `start_time` (float): 开始时间戳(包含)
-- `end_time` (float): 结束时间戳(包含)
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-- `filter_command` (bool): 是否过滤命令消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 4. 获取指定聊天中指定用户在指定时间范围内的消息
-```python
-def get_messages_by_time_in_chat_for_users(
- chat_id: str,
- start_time: float,
- end_time: float,
- person_ids: List[str],
- limit: int = 0,
- limit_mode: str = "latest",
-) -> List[Dict[str, Any]]:
-```
-获取指定聊天中指定用户在指定时间范围内的消息。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `person_ids` (List[str]): 用户ID列表
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 5. 随机选择一个聊天,返回该聊天在指定时间范围内的消息
-```python
-def get_random_chat_messages(
- start_time: float,
- end_time: float,
- limit: int = 0,
- limit_mode: str = "latest",
- filter_mai: bool = False,
-) -> List[Dict[str, Any]]:
-```
-随机选择一个聊天,返回该聊天在指定时间范围内的消息。
-
-**Args:**
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 6. 获取指定用户在所有聊天中指定时间范围内的消息
-```python
-def get_messages_by_time_for_users(
- start_time: float,
- end_time: float,
- person_ids: List[str],
- limit: int = 0,
- limit_mode: str = "latest",
-) -> List[Dict[str, Any]]:
-```
-获取指定用户在所有聊天中指定时间范围内的消息。
-
-**Args:**
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `person_ids` (List[str]): 用户ID列表
-- `limit` (int): 限制返回消息数量,0为不限制
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 7. 获取指定时间戳之前的消息
-```python
-def get_messages_before_time(
- timestamp: float,
- limit: int = 0,
- filter_mai: bool = False,
-) -> List[Dict[str, Any]]:
-```
-获取指定时间戳之前的消息。
-
-**Args:**
-- `timestamp` (float): 时间戳
-- `limit` (int): 限制返回消息数量,0为不限制
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 8. 获取指定聊天中指定时间戳之前的消息
-```python
-def get_messages_before_time_in_chat(
- chat_id: str,
- timestamp: float,
- limit: int = 0,
- filter_mai: bool = False,
-) -> List[Dict[str, Any]]:
-```
-获取指定聊天中指定时间戳之前的消息。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `timestamp` (float): 时间戳
-- `limit` (int): 限制返回消息数量,0为不限制
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 9. 获取指定用户在指定时间戳之前的消息
-```python
-def get_messages_before_time_for_users(
- timestamp: float,
- person_ids: List[str],
- limit: int = 0,
-) -> List[Dict[str, Any]]:
-```
-获取指定用户在指定时间戳之前的消息。
-
-**Args:**
-- `timestamp` (float): 时间戳
-- `person_ids` (List[str]): 用户ID列表
-- `limit` (int): 限制返回消息数量,0为不限制
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 10. 获取指定聊天中最近一段时间的消息
-```python
-def get_recent_messages(
- chat_id: str,
- hours: float = 24.0,
- limit: int = 100,
- limit_mode: str = "latest",
- filter_mai: bool = False,
-) -> List[Dict[str, Any]]:
-```
-获取指定聊天中最近一段时间的消息。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `hours` (float): 最近多少小时,默认24小时
-- `limit` (int): 限制返回消息数量,默认100条
-- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
-- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
-
-**Returns:**
-- `List[Dict[str, Any]]` - 消息列表
-
-
-### 11. 计算指定聊天中从开始时间到结束时间的新消息数量
-```python
-def count_new_messages(
- chat_id: str,
- start_time: float = 0.0,
- end_time: Optional[float] = None,
-) -> int:
-```
-计算指定聊天中从开始时间到结束时间的新消息数量。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `start_time` (float): 开始时间戳
-- `end_time` (Optional[float]): 结束时间戳,如果为None则使用当前时间
-
-**Returns:**
-- `int` - 新消息数量
-
-
-### 12. 计算指定聊天中指定用户从开始时间到结束时间的新消息数量
-```python
-def count_new_messages_for_users(
- chat_id: str,
- start_time: float,
- end_time: float,
- person_ids: List[str],
-) -> int:
-```
-计算指定聊天中指定用户从开始时间到结束时间的新消息数量。
-
-**Args:**
-- `chat_id` (str): 聊天ID
-- `start_time` (float): 开始时间戳
-- `end_time` (float): 结束时间戳
-- `person_ids` (List[str]): 用户ID列表
-
-**Returns:**
-- `int` - 新消息数量
-
-
-### 13. 将消息列表构建成可读的字符串
-```python
-def build_readable_messages_to_str(
- messages: List[Dict[str, Any]],
- replace_bot_name: bool = True,
- merge_messages: bool = False,
- timestamp_mode: str = "relative",
- read_mark: float = 0.0,
- truncate: bool = False,
- show_actions: bool = False,
-) -> str:
-```
-将消息列表构建成可读的字符串。
-
-**Args:**
-- `messages` (List[Dict[str, Any]]): 消息列表
-- `replace_bot_name` (bool): 是否将机器人的名称替换为"你"
-- `merge_messages` (bool): 是否合并连续消息
-- `timestamp_mode` (str): 时间戳显示模式,`"relative"`或`"absolute"`
-- `read_mark` (float): 已读标记时间戳,用于分割已读和未读消息
-- `truncate` (bool): 是否截断长消息
-- `show_actions` (bool): 是否显示动作记录
-
-**Returns:**
-- `str` - 格式化后的可读字符串
-
-
-### 14. 将消息列表构建成可读的字符串,并返回详细信息
-```python
-async def build_readable_messages_with_details(
- messages: List[Dict[str, Any]],
- replace_bot_name: bool = True,
- merge_messages: bool = False,
- timestamp_mode: str = "relative",
- truncate: bool = False,
-) -> Tuple[str, List[Tuple[float, str, str]]]:
-```
-将消息列表构建成可读的字符串,并返回详细信息。
-
-**Args:**
-- `messages` (List[Dict[str, Any]]): 消息列表
-- `replace_bot_name` (bool): 是否将机器人的名称替换为"你"
-- `merge_messages` (bool): 是否合并连续消息
-- `timestamp_mode` (str): 时间戳显示模式,`"relative"`或`"absolute"`
-- `truncate` (bool): 是否截断长消息
-
-**Returns:**
-- `Tuple[str, List[Tuple[float, str, str]]]` - 格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容)
-
-
-### 15. 从消息列表中提取不重复的用户ID列表
-```python
-async def get_person_ids_from_messages(
- messages: List[Dict[str, Any]],
-) -> List[str]:
-```
-从消息列表中提取不重复的用户ID列表。
-
-**Args:**
-- `messages` (List[Dict[str, Any]]): 消息列表
-
-**Returns:**
-- `List[str]` - 用户ID列表
-
-
-### 16. 从消息列表中移除机器人的消息
-```python
-def filter_mai_messages(
- messages: List[Dict[str, Any]],
-) -> List[Dict[str, Any]]:
-```
-从消息列表中移除机器人的消息。
-
-**Args:**
-- `messages` (List[Dict[str, Any]]): 消息列表,每个元素是消息字典
-
-**Returns:**
-- `List[Dict[str, Any]]` - 过滤后的消息列表
-
-## 注意事项
-
-1. **时间戳格式**:所有时间参数都使用Unix时间戳(float类型)
-2. **异步函数**:部分函数是异步函数,需要使用 `await`
-3. **性能考虑**:查询大量消息时建议设置合理的 `limit` 参数
-4. **消息格式**:返回的消息是字典格式,包含时间戳、发送者、内容等信息
-5. **用户ID**:`person_ids` 参数接受字符串列表,用于筛选特定用户的消息
\ No newline at end of file
diff --git a/docs-src/plugins/api/person-api.md b/docs-src/plugins/api/person-api.md
deleted file mode 100644
index f97498dc..00000000
--- a/docs-src/plugins/api/person-api.md
+++ /dev/null
@@ -1,119 +0,0 @@
-# 个人信息API
-
-个人信息API模块提供用户信息查询和管理功能,让插件能够获取和使用用户的相关信息。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import person_api
-# 或者
-from src.plugin_system import person_api
-```
-
-## 主要功能
-
-### 1. Person ID 获取
-```python
-def get_person_id(platform: str, user_id: int) -> str:
-```
-根据平台和用户ID获取person_id
-
-**Args:**
-- `platform`:平台名称,如 "qq", "telegram" 等
-- `user_id`:用户ID
-
-**Returns:**
-- `str`:唯一的person_id(MD5哈希值)
-
-#### 示例
-```python
-person_id = person_api.get_person_id("qq", 123456)
-```
-
-### 2. 用户信息查询
-```python
-async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any:
-```
-查询单个用户信息字段值
-
-**Args:**
-- `person_id`:用户的唯一标识ID
-- `field_name`:要获取的字段名
-- `default`:字段值不存在时的默认值
-
-**Returns:**
-- `Any`:字段值或默认值
-
-#### 示例
-```python
-nickname = await person_api.get_person_value(person_id, "nickname", "未知用户")
-impression = await person_api.get_person_value(person_id, "impression")
-```
-
-### 3. 批量用户信息查询
-```python
-async def get_person_values(person_id: str, field_names: list, default_dict: Optional[dict] = None) -> dict:
-```
-批量获取用户信息字段值
-
-**Args:**
-- `person_id`:用户的唯一标识ID
-- `field_names`:要获取的字段名列表
-- `default_dict`:默认值字典,键为字段名,值为默认值
-
-**Returns:**
-- `dict`:字段名到值的映射字典
-
-#### 示例
-```python
-values = await person_api.get_person_values(
- person_id,
- ["nickname", "impression", "know_times"],
- {"nickname": "未知用户", "know_times": 0}
-)
-```
-
-### 4. 判断用户是否已知
-```python
-async def is_person_known(platform: str, user_id: int) -> bool:
-```
-判断是否认识某个用户
-
-**Args:**
-- `platform`:平台名称
-- `user_id`:用户ID
-
-**Returns:**
-- `bool`:是否认识该用户
-
-### 5. 根据用户名获取Person ID
-```python
-def get_person_id_by_name(person_name: str) -> str:
-```
-根据用户名获取person_id
-
-**Args:**
-- `person_name`:用户名
-
-**Returns:**
-- `str`:person_id,如果未找到返回空字符串
-
-## 常用字段说明
-
-### 基础信息字段
-- `nickname`:用户昵称
-- `platform`:平台信息
-- `user_id`:用户ID
-
-### 关系信息字段
-- `impression`:对用户的印象
-- `points`: 用户特征点
-
-其他字段可以参考`PersonInfo`类的属性(位于`src.common.database.database_model`)
-
-## 注意事项
-
-1. **异步操作**:部分查询函数都是异步的,需要使用`await`
-2. **性能考虑**:批量查询优于单个查询
-3. **隐私保护**:确保用户信息的使用符合隐私政策
-4. **数据一致性**:person_id是用户的唯一标识,应妥善保存和使用
\ No newline at end of file
diff --git a/docs-src/plugins/api/plugin-manage-api.md b/docs-src/plugins/api/plugin-manage-api.md
deleted file mode 100644
index 688ea9ef..00000000
--- a/docs-src/plugins/api/plugin-manage-api.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# 插件管理API
-
-插件管理API模块提供了对插件的加载、卸载、重新加载以及目录管理功能。
-
-## 导入方式
-```python
-from src.plugin_system.apis import plugin_manage_api
-# 或者
-from src.plugin_system import plugin_manage_api
-```
-
-## 功能概述
-
-插件管理API主要提供以下功能:
-- **插件查询** - 列出当前加载的插件或已注册的插件。
-- **插件管理** - 加载、卸载、重新加载插件。
-- **插件目录管理** - 添加插件目录并重新扫描。
-
-## 主要功能
-
-### 1. 列出当前加载的插件
-```python
-def list_loaded_plugins() -> List[str]:
-```
-列出所有当前加载的插件。
-
-**Returns:**
-- `List[str]` - 当前加载的插件名称列表。
-
-### 2. 列出所有已注册的插件
-```python
-def list_registered_plugins() -> List[str]:
-```
-列出所有已注册的插件。
-
-**Returns:**
-- `List[str]` - 已注册的插件名称列表。
-
-### 3. 获取插件路径
-```python
-def get_plugin_path(plugin_name: str) -> str:
-```
-获取指定插件的路径。
-
-**Args:**
-- `plugin_name` (str): 要查询的插件名称。
-**Returns:**
-- `str` - 插件的路径,如果插件不存在则 raise ValueError。
-
-### 4. 卸载指定的插件
-```python
-async def remove_plugin(plugin_name: str) -> bool:
-```
-卸载指定的插件。
-
-**Args:**
-- `plugin_name` (str): 要卸载的插件名称。
-
-**Returns:**
-- `bool` - 卸载是否成功。
-
-### 5. 重新加载指定的插件
-```python
-async def reload_plugin(plugin_name: str) -> bool:
-```
-重新加载指定的插件。
-
-**Args:**
-- `plugin_name` (str): 要重新加载的插件名称。
-
-**Returns:**
-- `bool` - 重新加载是否成功。
-
-### 6. 加载指定的插件
-```python
-def load_plugin(plugin_name: str) -> Tuple[bool, int]:
-```
-加载指定的插件。
-
-**Args:**
-- `plugin_name` (str): 要加载的插件名称。
-
-**Returns:**
-- `Tuple[bool, int]` - 加载是否成功,成功或失败的个数。
-
-### 7. 添加插件目录
-```python
-def add_plugin_directory(plugin_directory: str) -> bool:
-```
-添加插件目录。
-
-**Args:**
-- `plugin_directory` (str): 要添加的插件目录路径。
-
-**Returns:**
-- `bool` - 添加是否成功。
-
-### 8. 重新扫描插件目录
-```python
-def rescan_plugin_directory() -> Tuple[int, int]:
-```
-重新扫描插件目录,加载新插件。
-
-**Returns:**
-- `Tuple[int, int]` - 成功加载的插件数量和失败的插件数量。
\ No newline at end of file
diff --git a/docs-src/plugins/api/send-api.md b/docs-src/plugins/api/send-api.md
deleted file mode 100644
index 8b3c607f..00000000
--- a/docs-src/plugins/api/send-api.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# 消息发送API
-
-消息发送API模块专门负责发送各种类型的消息,支持文本、表情包、图片等多种消息类型。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import send_api
-# 或者
-from src.plugin_system import send_api
-```
-
-## 主要功能
-
-### 1. 发送文本消息
-```python
-async def text_to_stream(
- text: str,
- stream_id: str,
- typing: bool = False,
- reply_to: str = "",
- storage_message: bool = True,
-) -> bool:
-```
-发送文本消息到指定的流
-
-**Args:**
-- `text` (str): 要发送的文本内容
-- `stream_id` (str): 聊天流ID
-- `typing` (bool): 是否显示正在输入
-- `reply_to` (str): 回复消息,格式为"发送者:消息内容"
-- `storage_message` (bool): 是否存储消息到数据库
-
-**Returns:**
-- `bool` - 是否发送成功
-
-### 2. 发送表情包
-```python
-async def emoji_to_stream(emoji_base64: str, stream_id: str, storage_message: bool = True) -> bool:
-```
-向指定流发送表情包。
-
-**Args:**
-- `emoji_base64` (str): 表情包的base64编码
-- `stream_id` (str): 聊天流ID
-- `storage_message` (bool): 是否存储消息到数据库
-
-**Returns:**
-- `bool` - 是否发送成功
-
-### 3. 发送图片
-```python
-async def image_to_stream(image_base64: str, stream_id: str, storage_message: bool = True) -> bool:
-```
-向指定流发送图片。
-
-**Args:**
-- `image_base64` (str): 图片的base64编码
-- `stream_id` (str): 聊天流ID
-- `storage_message` (bool): 是否存储消息到数据库
-
-**Returns:**
-- `bool` - 是否发送成功
-
-### 4. 发送命令
-```python
-async def command_to_stream(command: Union[str, dict], stream_id: str, storage_message: bool = True, display_message: str = "") -> bool:
-```
-向指定流发送命令。
-
-**Args:**
-- `command` (Union[str, dict]): 命令内容
-- `stream_id` (str): 聊天流ID
-- `storage_message` (bool): 是否存储消息到数据库
-- `display_message` (str): 显示消息
-
-**Returns:**
-- `bool` - 是否发送成功
-
-### 5. 发送自定义类型消息
-```python
-async def custom_to_stream(
- message_type: str,
- content: str,
- stream_id: str,
- display_message: str = "",
- typing: bool = False,
- reply_to: str = "",
- storage_message: bool = True,
- show_log: bool = True,
-) -> bool:
-```
-向指定流发送自定义类型消息。
-
-**Args:**
-- `message_type` (str): 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
-- `content` (str): 消息内容(通常是base64编码或文本)
-- `stream_id` (str): 聊天流ID
-- `display_message` (str): 显示消息
-- `typing` (bool): 是否显示正在输入
-- `reply_to` (str): 回复消息,格式为"发送者:消息内容"
-- `storage_message` (bool): 是否存储消息到数据库
-- `show_log` (bool): 是否显示日志
-
-**Returns:**
-- `bool` - 是否发送成功
-
-## 使用示例
-
-### 1. 基础文本发送,并回复消息
-
-```python
-from src.plugin_system.apis import send_api
-
-async def send_hello(chat_stream):
- """发送问候消息"""
-
- success = await send_api.text_to_stream(
- text="Hello, world!",
- stream_id=chat_stream.stream_id,
- typing=True,
- reply_to="User:How are you?",
- storage_message=True
- )
-
- return success
-```
-
-### 2. 发送表情包
-
-```python
-from src.plugin_system.apis import emoji_api
-async def send_emoji_reaction(chat_stream, emotion):
- """根据情感发送表情包"""
- # 获取表情包
- emoji_result = await emoji_api.get_by_emotion(emotion)
- if not emoji_result:
- return False
-
- emoji_base64, description, matched_emotion = emoji_result
-
- # 发送表情包
- success = await send_api.emoji_to_stream(
- emoji_base64=emoji_base64,
- stream_id=chat_stream.stream_id,
- storage_message=False # 不存储到数据库
- )
-
- return success
-```
-
-## 消息类型说明
-
-### 支持的消息类型
-- `"text"`:纯文本消息
-- `"emoji"`:表情包消息
-- `"image"`:图片消息
-- `"command"`:命令消息
-- `"video"`:视频消息(如果支持)
-- `"audio"`:音频消息(如果支持)
-
-### 回复格式
-回复消息使用格式:`"发送者:消息内容"` 或 `"发送者:消息内容"`
-
-系统会自动查找匹配的原始消息并进行回复。
-
-## 注意事项
-
-1. **异步操作**:所有发送函数都是异步的,必须使用`await`
-2. **错误处理**:发送失败时返回False,成功时返回True
-3. **发送频率**:注意控制发送频率,避免被平台限制
-4. **内容限制**:注意平台对消息内容和长度的限制
-5. **权限检查**:确保机器人有发送消息的权限
-6. **编码格式**:图片和表情包需要使用base64编码
-7. **存储选项**:可以选择是否将发送的消息存储到数据库
\ No newline at end of file
diff --git a/docs-src/plugins/api/tool-api.md b/docs-src/plugins/api/tool-api.md
deleted file mode 100644
index bd6e7d2e..00000000
--- a/docs-src/plugins/api/tool-api.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# 工具API
-
-工具API模块提供了获取和管理工具实例的功能,让插件能够访问系统中注册的工具。
-
-## 导入方式
-
-```python
-from src.plugin_system.apis import tool_api
-# 或者
-from src.plugin_system import tool_api
-```
-
-## 主要功能
-
-### 1. 获取工具实例
-
-```python
-def get_tool_instance(tool_name: str) -> Optional[BaseTool]:
-```
-
-获取指定名称的工具实例。
-
-**Args**:
-- `tool_name`: 工具名称字符串
-
-**Returns**:
-- `Optional[BaseTool]`: 工具实例,如果工具不存在则返回 None
-
-### 2. 获取LLM可用的工具定义
-
-```python
-def get_llm_available_tool_definitions():
-```
-
-获取所有LLM可用的工具定义列表。
-
-**Returns**:
-- `List[Tuple[str, Dict[str, Any]]]`: 工具定义列表,每个元素为 `(工具名称, 工具定义字典)` 的元组
- - 其具体定义请参照[tool-components.md](../tool-components.md#属性说明)中的工具定义格式。
-#### 示例:
-
-```python
-# 获取所有LLM可用的工具定义
-tools = tool_api.get_llm_available_tool_definitions()
-for tool_name, tool_definition in tools:
- print(f"工具: {tool_name}")
- print(f"定义: {tool_definition}")
-```
-
-## 注意事项
-
-1. **工具存在性检查**:使用前请检查工具实例是否为 None
-2. **权限控制**:某些工具可能有使用权限限制
-3. **异步调用**:大多数工具方法是异步的,需要使用 await
-4. **错误处理**:调用工具时请做好异常处理
diff --git a/docs-src/plugins/command-components.md b/docs-src/plugins/command-components.md
deleted file mode 100644
index 77cc8acc..00000000
--- a/docs-src/plugins/command-components.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# 💻 Command组件详解
-
-## 📖 什么是Command
-
-Command是直接响应用户明确指令的组件,与Action不同,Command是**被动触发**的,当用户输入特定格式的命令时立即执行。
-
-Command通过正则表达式匹配用户输入,提供确定性的功能服务。
-
-### 🎯 Command的特点
-
-- 🎯 **确定性执行**:匹配到命令立即执行,无随机性
-- ⚡ **即时响应**:用户主动触发,快速响应
-- 🔍 **正则匹配**:通过正则表达式精确匹配用户输入
-- 🛑 **拦截控制**:可以控制是否阻止消息继续处理
-- 📝 **参数解析**:支持从用户输入中提取参数
-
----
-
-## 🛠️ Command组件的基本结构
-
-首先,Command组件需要继承自`BaseCommand`类,并实现必要的方法。
-
-```python
-class ExampleCommand(BaseCommand):
- command_name = "example" # 命令名称,作为唯一标识符
- command_description = "这是一个示例命令" # 命令描述
- command_pattern = r"" # 命令匹配的正则表达式
-
- async def execute(self) -> Tuple[bool, Optional[str], bool]:
- """
- 执行Command的主要逻辑
-
- Returns:
- Tuple[bool, str, bool]:
- - 第一个bool表示是否成功执行
- - 第二个str是执行结果消息
- - 第三个bool表示是否需要阻止消息继续处理
- """
- # ---- 执行命令的逻辑 ----
- return True, "执行成功", False
-```
-**`command_pattern`**: 该Command匹配的正则表达式,用于精确匹配用户输入。
-
-请注意:如果希望能获取到命令中的参数,请在正则表达式中使用有命名的捕获组,例如`(?Ppattern)`。
-
-这样在匹配时,内部实现可以使用`re.match.groupdict()`方法获取到所有捕获组的参数,并以字典的形式存储在`self.matched_groups`中。
-
-### 匹配样例
-假设我们有一个命令`/example param1=value1 param2=value2`,对应的正则表达式可以是:
-
-```python
-class ExampleCommand(BaseCommand):
- command_name = "example"
- command_description = "这是一个示例命令"
- command_pattern = r"/example (?P\w+) (?P\w+)"
-
- async def execute(self) -> Tuple[bool, Optional[str], bool]:
- # 获取匹配的参数
- param1 = self.matched_groups.get("param1")
- param2 = self.matched_groups.get("param2")
-
- # 执行逻辑
- return True, f"参数1: {param1}, 参数2: {param2}", False
-```
-
----
-
-## Command 内置方法说明
-```python
-class BaseCommand:
- def get_config(self, key: str, default=None):
- """获取插件配置值,使用嵌套键访问"""
-
- async def send_text(self, content: str, reply_to: str = "") -> bool:
- """发送回复消息"""
-
- async def send_type(self, message_type: str, content: str, display_message: str = "", typing: bool = False, reply_to: str = "") -> bool:
- """发送指定类型的回复消息到当前聊天环境"""
-
- async def send_command(self, command_name: str, args: Optional[dict] = None, display_message: str = "", storage_message: bool = True) -> bool:
- """发送命令消息"""
-
- async def send_emoji(self, emoji_base64: str) -> bool:
- """发送表情包"""
-
- async def send_image(self, image_base64: str) -> bool:
- """发送图片"""
-```
-具体参数与用法参见`BaseCommand`基类的定义。
\ No newline at end of file
diff --git a/docs-src/plugins/configuration-guide.md b/docs-src/plugins/configuration-guide.md
deleted file mode 100644
index ef334472..00000000
--- a/docs-src/plugins/configuration-guide.md
+++ /dev/null
@@ -1,347 +0,0 @@
-# ⚙️ 插件配置完整指南
-
-本文档将全面指导你如何为你的插件**定义配置**和在组件中**访问配置**,帮助你构建一个健壮、规范且自带文档的配置系统。
-
-> **🚨 重要原则:任何时候都不要手动创建 config.toml 文件!**
->
-> 系统会根据你在代码中定义的 `config_schema` 自动生成配置文件。手动创建配置文件会破坏自动化流程,导致配置不一致、缺失注释和文档等问题。
-
-## 配置版本管理
-
-### 🎯 版本管理概述
-
-插件系统提供了强大的**配置版本管理机制**,可以在插件升级时自动处理配置文件的迁移和更新,确保配置结构始终与代码保持同步。
-
-### 🔄 配置版本管理工作流程
-
-```mermaid
-graph TD
- A[插件加载] --> B[检查配置文件]
- B --> C{配置文件存在?}
- C -->|不存在| D[生成默认配置]
- C -->|存在| E[读取当前版本]
- E --> F{有版本信息?}
- F -->|无版本| G[跳过版本检查
直接加载配置]
- F -->|有版本| H{版本匹配?}
- H -->|匹配| I[直接加载配置]
- H -->|不匹配| J[配置迁移]
- J --> K[生成新配置结构]
- K --> L[迁移旧配置值]
- L --> M[保存迁移后配置]
- M --> N[配置加载完成]
- D --> N
- G --> N
- I --> N
-
- style J fill:#FFB6C1
- style K fill:#90EE90
- style G fill:#87CEEB
- style N fill:#DDA0DD
-```
-
-### 📊 版本管理策略
-
-#### 1. 配置版本定义
-
-在 `config_schema` 的 `plugin` 节中定义 `config_version`:
-
-```python
-config_schema = {
- "plugin": {
- "enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
- "config_version": ConfigField(type=str, default="1.2.0", description="配置文件版本"),
- },
- # 其他配置...
-}
-```
-
-#### 2. 版本检查行为
-
-- **无版本信息** (`config_version` 不存在)
- - 系统会**跳过版本检查**,直接加载现有配置
- - 适用于旧版本插件的兼容性处理
- - 日志显示:`配置文件无版本信息,跳过版本检查`
-
-- **有版本信息** (存在 `config_version` 字段)
- - 比较当前版本与期望版本
- - 版本不匹配时自动执行配置迁移
- - 版本匹配时直接加载配置
-
-#### 3. 配置迁移过程
-
-当检测到版本不匹配时,系统会:
-
-1. **生成新配置结构** - 根据最新的 `config_schema` 生成新的配置结构
-2. **迁移配置值** - 将旧配置文件中的值迁移到新结构中
-3. **处理新增字段** - 新增的配置项使用默认值
-4. **更新版本号** - `config_version` 字段自动更新为最新版本
-5. **保存配置文件** - 迁移后的配置直接覆盖原文件**(不保留备份)**
-
-### 🔧 实际使用示例
-
-#### 版本升级场景
-
-假设你的插件从 v1.0 升级到 v1.1,新增了权限管理功能:
-
-**旧版本配置 (v1.0.0):**
-```toml
-[plugin]
-enabled = true
-config_version = "1.0.0"
-
-[mute]
-min_duration = 60
-max_duration = 3600
-```
-
-**新版本Schema (v1.1.0):**
-```python
-config_schema = {
- "plugin": {
- "enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
- "config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),
- },
- "mute": {
- "min_duration": ConfigField(type=int, default=60, description="最短禁言时长(秒)"),
- "max_duration": ConfigField(type=int, default=2592000, description="最长禁言时长(秒)"),
- },
- "permissions": { # 新增的配置节
- "allowed_users": ConfigField(type=list, default=[], description="允许的用户列表"),
- "allowed_groups": ConfigField(type=list, default=[], description="允许的群组列表"),
- }
-}
-```
-
-**迁移后配置 (v1.1.0):**
-```toml
-[plugin]
-enabled = true # 保留原值
-config_version = "1.1.0" # 自动更新
-
-[mute]
-min_duration = 60 # 保留原值
-max_duration = 3600 # 保留原值
-
-[permissions] # 新增节,使用默认值
-allowed_users = []
-allowed_groups = []
-```
-
-#### 无版本配置的兼容性
-
-对于没有版本信息的旧配置文件:
-
-**旧配置文件(无版本):**
-```toml
-[plugin]
-enabled = true
-# 没有 config_version 字段
-
-[mute]
-min_duration = 120
-```
-
-**系统行为:**
-- 检测到无版本信息
-- 跳过版本检查和迁移
-- 直接加载现有配置
-- 新增的配置项在代码中使用默认值访问
-- 系统会详细记录配置迁移过程。
-
-### ⚠️ 重要注意事项
-
-#### 1. 版本号管理
-- 当你修改 `config_schema` 时,**必须同步更新** `config_version`
-- 请使用语义化版本号 (例如:`1.0.0`, `1.1.0`, `2.0.0`)
-
-#### 2. 迁移策略
-- **保留原值优先**: 迁移时优先保留用户的原有配置值
-- **新增字段默认值**: 新增的配置项使用Schema中定义的默认值
-- **移除字段警告**: 如果某个配置项在新版本中被移除,会在日志中显示警告
-
-#### 3. 兼容性考虑
-- **旧版本兼容**: 无版本信息的配置文件会跳过版本检查
-- **不保留备份**: 迁移后直接覆盖原配置文件,不保留备份
-- **失败安全**: 如果迁移过程中出现错误,会回退到原配置
-
-## 配置定义
-
-配置的定义在你的插件主类(继承自 `BasePlugin`)中完成,主要通过两个类属性:
-
-1. `config_section_descriptions`: 一个字典,用于描述配置文件的各个区段(`[section]`)。
-2. `config_schema`: 核心部分,一个嵌套字典,用于定义每个区段下的具体配置项。
-
-### `ConfigField`:配置项的基石
-
-每个配置项都通过一个 `ConfigField` 对象来定义。
-
-```python
-from dataclasses import dataclass
-from src.plugin_system.base.config_types import ConfigField
-
-@dataclass
-class ConfigField:
- """配置字段定义"""
- type: type # 字段类型 (例如 str, int, float, bool, list)
- default: Any # 默认值
- description: str # 字段描述 (将作为注释生成到配置文件中)
- example: Optional[str] = None # 示例值 (可选)
- required: bool = False # 是否必需 (可选, 主要用于文档提示)
- choices: Optional[List[Any]] = None # 可选值列表 (可选)
-```
-
-### 配置示例
-
-让我们以一个功能丰富的 `MutePlugin` 为例,看看如何定义它的配置。
-
-```python
-# src/plugins/built_in/mute_plugin/plugin.py
-
-from src.plugin_system import BasePlugin, register_plugin, ConfigField
-from typing import List, Tuple, Type
-
-@register_plugin
-class MutePlugin(BasePlugin):
- """禁言插件"""
-
- # 这里是插件基本信息,略去
-
- # 步骤1: 定义配置节的描述
- config_section_descriptions = {
- "plugin": "插件启用配置",
- "components": "组件启用控制",
- "mute": "核心禁言功能配置",
- "smart_mute": "智能禁言Action的专属配置",
- "logging": "日志记录相关配置"
- }
-
- # 步骤2: 使用ConfigField定义详细的配置Schema
- config_schema = {
- "plugin": {
- "enabled": ConfigField(type=bool, default=False, description="是否启用插件")
- },
- "components": {
- "enable_smart_mute": ConfigField(type=bool, default=True, description="是否启用智能禁言Action"),
- "enable_mute_command": ConfigField(type=bool, default=False, description="是否启用禁言命令Command")
- },
- "mute": {
- "min_duration": ConfigField(type=int, default=60, description="最短禁言时长(秒)"),
- "max_duration": ConfigField(type=int, default=2592000, description="最长禁言时长(秒),默认30天"),
- "templates": ConfigField(
- type=list,
- default=["好的,禁言 {target} {duration},理由:{reason}", "收到,对 {target} 执行禁言 {duration}"],
- description="成功禁言后发送的随机消息模板"
- )
- },
- "smart_mute": {
- "keyword_sensitivity": ConfigField(
- type=str,
- default="normal",
- description="关键词激活的敏感度",
- choices=["low", "normal", "high"] # 定义可选值
- ),
- },
- "logging": {
- "level": ConfigField(
- type=str,
- default="INFO",
- description="日志记录级别",
- choices=["DEBUG", "INFO", "WARNING", "ERROR"]
- ),
- "prefix": ConfigField(type=str, default="[MutePlugin]", description="日志记录前缀", example="[MyMutePlugin]")
- }
- }
-
- # 这里是插件方法,略去
-```
-
-当 `mute_plugin` 首次加载且其目录中不存在 `config.toml` 时,系统会自动创建以下文件:
-
-```toml
-# mute_plugin - 自动生成的配置文件
-# 群聊禁言管理插件,提供智能禁言功能
-
-# 插件启用配置
-[plugin]
-
-# 是否启用插件
-enabled = false
-
-
-# 组件启用控制
-[components]
-
-# 是否启用智能禁言Action
-enable_smart_mute = true
-
-# 是否启用禁言命令Command
-enable_mute_command = false
-
-
-# 核心禁言功能配置
-[mute]
-
-# 最短禁言时长(秒)
-min_duration = 60
-
-# 最长禁言时长(秒),默认30天
-max_duration = 2592000
-
-# 成功禁言后发送的随机消息模板
-templates = ["好的,禁言 {target} {duration},理由:{reason}", "收到,对 {target} 执行禁言 {duration}"]
-
-
-# 智能禁言Action的专属配置
-[smart_mute]
-
-# 关键词激活的敏感度
-# 可选值: low, normal, high
-keyword_sensitivity = "normal"
-
-
-# 日志记录相关配置
-[logging]
-
-# 日志记录级别
-# 可选值: DEBUG, INFO, WARNING, ERROR
-level = "INFO"
-
-# 日志记录前缀
-# 示例: [MyMutePlugin]
-prefix = "[MutePlugin]"
-```
-
----
-
-## 配置访问
-
-如果你想要在你的组件中访问配置,可以通过组件内置的 `get_config()` 方法访问配置。
-
-其参数为一个命名空间化的字符串。以上面的 `MutePlugin` 为例,你可以这样访问配置:
-
-```python
-enable_smart_mute = self.get_config("components.enable_smart_mute", True)
-```
-
-如果尝试访问了一个不存在的配置项,系统会自动返回默认值(你传递的)或者 `None`。
-
----
-
-## 最佳实践与注意事项
-
-
-**🚨 核心原则:永远不要手动创建 config.toml 文件!**
-
-1. **🔥 绝不手动创建配置文件**: **任何时候都不要手动创建 `config.toml` 文件**!必须通过在 `plugin.py` 中定义 `config_schema` 让系统自动生成。
- - ❌ **禁止**:`touch config.toml`、手动编写配置文件
- - ✅ **正确**:定义 `config_schema`,启动插件,让系统自动生成
-
-2. **Schema优先**: 所有配置项都必须在 `config_schema` 中声明,包括类型、默认值和描述。
-
-3. **描述清晰**: 为每个 `ConfigField` 和 `config_section_descriptions` 编写清晰、准确的描述。这会直接成为你的插件文档的一部分。
-
-4. **提供合理默认值**: 确保你的插件在默认配置下就能正常运行(或处于一个安全禁用的状态)。
-
-5. **gitignore**: 将 `plugins/*/config.toml` 或 `src/plugins/built_in/*/config.toml` 加入 `.gitignore`,以避免提交个人敏感信息。
-
-6. **配置文件只供修改**: 自动生成的 `config.toml` 文件只应该被用户**修改**,而不是从零创建。
\ No newline at end of file
diff --git a/docs-src/plugins/dependency-management.md b/docs-src/plugins/dependency-management.md
deleted file mode 100644
index 4bb4ed00..00000000
--- a/docs-src/plugins/dependency-management.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# 📦 插件依赖管理系统
-
-现在的Python依赖包管理依然存在问题,请保留你的`python_dependencies`属性,等待后续重构。
-
-## 📚 详细教程
-
-### PythonDependency 类详解
-
-`PythonDependency`是依赖声明的核心类:
-
-```python
-PythonDependency(
- package_name="PIL", # 导入时的包名
- version=">=11.2.0", # 版本要求
- optional=False, # 是否为可选依赖
- description="图像处理库", # 依赖描述
- install_name="pillow" # pip安装时的包名(可选)
-)
-```
-
-#### 参数说明
-
-| 参数 | 类型 | 必需 | 说明 |
-|------|------|------|------|
-| `package_name` | str | ✅ | Python导入时使用的包名(如`requests`) |
-| `version` | str | ❌ | 版本要求,使用pip格式(如`>=1.0.0`, `==2.1.3`) |
-| `optional` | bool | ❌ | 是否为可选依赖,默认`False` |
-| `description` | str | ❌ | 依赖的用途描述 |
-| `install_name` | str | ❌ | pip安装时的包名,默认与`package_name`相同,用于处理安装名称和导入名称不一致的情况 |
-
-#### 版本格式示例
-
-```python
-# 常用版本格式
-PythonDependency("requests", ">=2.25.0") # 最小版本
-PythonDependency("numpy", ">=1.20.0,<2.0.0") # 版本范围
-PythonDependency("pillow", "==8.3.2") # 精确版本
-PythonDependency("scipy", ">=1.7.0,!=1.8.0") # 排除特定版本
-```
-
diff --git a/docs-src/plugins/image/quick-start/1750326700269.png b/docs-src/plugins/image/quick-start/1750326700269.png
deleted file mode 100644
index 1dc4f19b..00000000
Binary files a/docs-src/plugins/image/quick-start/1750326700269.png and /dev/null differ
diff --git a/docs-src/plugins/image/quick-start/1750332508760.png b/docs-src/plugins/image/quick-start/1750332508760.png
deleted file mode 100644
index 924b9b6b..00000000
Binary files a/docs-src/plugins/image/quick-start/1750332508760.png and /dev/null differ
diff --git a/docs-src/plugins/index.md b/docs-src/plugins/index.md
deleted file mode 100644
index 2454c98a..00000000
--- a/docs-src/plugins/index.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# MaiBot插件开发文档
-
-> 欢迎来到MaiBot插件系统开发文档!这里是你开始插件开发旅程的最佳起点。
-
-## 新手入门
-
-- [📖 快速开始指南](quick-start.md) - 快速创建你的第一个插件
-
-## 组件功能详解
-
-- [🧱 Action组件详解](action-components.md) - 掌握最核心的Action组件
-- [💻 Command组件详解](command-components.md) - 学习直接响应命令的组件
-- [🔧 Tool组件详解](tool-components.md) - 了解如何扩展信息获取能力
-- [⚙️ 配置文件系统指南](configuration-guide.md) - 学会使用自动生成的插件配置文件
-- [📄 Manifest系统指南](manifest-guide.md) - 了解插件元数据管理和配置架构
-
-Command vs Action 选择指南
-
-1. 使用Command的场景
-
-- ✅ 用户需要明确调用特定功能
-- ✅ 需要精确的参数控制
-- ✅ 管理和配置操作
-- ✅ 查询和信息显示
-- ✅ 系统维护命令
-
-2. 使用Action的场景
-
-- ✅ 增强麦麦的智能行为
-- ✅ 根据上下文自动触发
-- ✅ 情绪和表情表达
-- ✅ 智能建议和帮助
-- ✅ 随机化的互动
-
-
-## API浏览
-
-### 消息发送与处理API
-- [📤 发送API](api/send-api.md) - 各种类型消息发送接口
-- [消息API](api/message-api.md) - 消息获取,消息构建,消息查询接口
-- [聊天流API](api/chat-api.md) - 聊天流管理和查询接口
-
-### AI与生成API
-- [LLM API](api/llm-api.md) - 大语言模型交互接口,可以使用内置LLM生成内容
-- [✨ 回复生成器API](api/generator-api.md) - 智能回复生成接口,可以使用内置风格化生成器
-
-### 表情包API
-- [😊 表情包API](api/emoji-api.md) - 表情包选择和管理接口
-
-### 关系系统API
-- [人物信息API](api/person-api.md) - 用户信息,处理麦麦认识的人和关系的接口
-
-### 数据与配置API
-- [🗄️ 数据库API](api/database-api.md) - 数据库操作接口
-- [⚙️ 配置API](api/config-api.md) - 配置读取和用户信息接口
-
-### 插件和组件管理API
-- [🔌 插件API](api/plugin-manage-api.md) - 插件加载和管理接口
-- [🧩 组件API](api/component-manage-api.md) - 组件注册和管理接口
-
-### 日志API
-- [📜 日志API](api/logging-api.md) - logger实例获取接口
-### 工具API
-- [🔧 工具API](api/tool-api.md) - tool获取接口
-
-
-
-## 支持
-
-> 如果你在文档中发现错误或需要补充,请:
-
-1. 检查最新的文档版本
-2. 查看相关示例代码
-3. 参考其他类似插件
-4. 提交文档仓库issue
-
-## 一个方便的小设计
-
-我们在`__init__.py`中定义了一个`__all__`变量,包含了所有需要导出的类和函数。
-这样在其他地方导入时,可以直接使用 `from src.plugin_system import *` 来导入所有插件相关的类和函数。
-或者你可以直接使用 `from src.plugin_system import BasePlugin, register_plugin, ComponentInfo` 之类的方式来导入你需要的部分。
\ No newline at end of file
diff --git a/docs-src/plugins/manifest-guide.md b/docs-src/plugins/manifest-guide.md
deleted file mode 100644
index d3dd746a..00000000
--- a/docs-src/plugins/manifest-guide.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# 📄 插件Manifest系统指南
-
-## 概述
-
-MaiBot插件系统现在强制要求每个插件都必须包含一个 `_manifest.json` 文件。这个文件描述了插件的基本信息、依赖关系、组件等重要元数据。
-
-### 🔄 配置架构:Manifest与Config的职责分离
-
-为了避免信息重复和提高维护性,我们采用了**双文件架构**:
-
-- **`_manifest.json`** - 插件的**静态元数据**
- - 插件身份信息(名称、版本、描述)
- - 开发者信息(作者、许可证、仓库)
- - 系统信息(兼容性、组件列表、分类)
-
-- **`config.toml`** - 插件的**运行时配置**
- - 启用状态 (`enabled`)
- - 功能参数配置
- - 用户可调整的行为设置
-
-这种分离确保了:
-- ✅ 元数据信息统一管理
-- ✅ 运行时配置灵活调整
-- ✅ 避免重复维护
-- ✅ 更清晰的职责划分
-
-## 🔧 Manifest文件结构
-
-### 必需字段
-
-以下字段是必需的,不能为空:
-
-```json
-{
- "manifest_version": 1,
- "name": "插件显示名称",
- "version": "1.0.0",
- "description": "插件功能描述",
- "author": {
- "name": "作者名称"
- }
-}
-```
-
-### 可选字段
-
-以下字段都是可选的,可以根据需要添加:
-
-```json
-{
- "license": "MIT",
- "host_application": {
- "min_version": "1.0.0",
- "max_version": "4.0.0"
- },
- "homepage_url": "https://github.com/your-repo",
- "repository_url": "https://github.com/your-repo",
- "keywords": ["关键词1", "关键词2"],
- "categories": ["分类1", "分类2"],
- "default_locale": "zh-CN",
- "locales_path": "_locales",
- "plugin_info": {
- "is_built_in": false,
- "plugin_type": "general",
- "components": [
- {
- "type": "action",
- "name": "组件名称",
- "description": "组件描述"
- }
- ]
- }
-}
-```
-
-## 🛠️ 管理工具
-
-### 使用manifest_tool.py
-
-我们提供了一个命令行工具来帮助管理manifest文件:
-
-```bash
-# 扫描缺少manifest的插件
-python scripts/manifest_tool.py scan src/plugins
-
-# 为插件创建最小化manifest文件
-python scripts/manifest_tool.py create-minimal src/plugins/my_plugin --name "我的插件" --author "作者"
-
-# 为插件创建完整manifest模板
-python scripts/manifest_tool.py create-complete src/plugins/my_plugin --name "我的插件"
-
-# 验证manifest文件
-python scripts/manifest_tool.py validate src/plugins/my_plugin
-```
-
-### 验证示例
-
-验证通过的示例:
-```
-✅ Manifest文件验证通过
-```
-
-验证失败的示例:
-```
-❌ 验证错误:
- - 缺少必需字段: name
- - 作者信息缺少name字段或为空
-⚠️ 验证警告:
- - 建议填写字段: license
- - 建议填写字段: keywords
-```
-
-## 🔄 迁移指南
-
-### 对于现有插件
-
-1. **检查缺少manifest的插件**:
- ```bash
- python scripts/manifest_tool.py scan src/plugins
- ```
-
-2. **为每个插件创建manifest**:
- ```bash
- python scripts/manifest_tool.py create-minimal src/plugins/your_plugin
- ```
-
-3. **编辑manifest文件**,填写正确的信息。
-
-4. **验证manifest**:
- ```bash
- python scripts/manifest_tool.py validate src/plugins/your_plugin
- ```
-
-### 对于新插件
-
-创建新插件时,建议的步骤:
-
-1. **创建插件目录和基本文件**
-2. **创建完整manifest模板**:
- ```bash
- python scripts/manifest_tool.py create-complete src/plugins/new_plugin
- ```
-3. **根据实际情况修改manifest文件**
-4. **编写插件代码**
-5. **验证manifest文件**
-
-## 📋 字段说明
-
-### 基本信息
-- `manifest_version`: manifest格式版本,当前为1
-- `name`: 插件显示名称(必需)
-- `version`: 插件版本号(必需)
-- `description`: 插件功能描述(必需)
-- `author`: 作者信息(必需)
- - `name`: 作者名称(必需)
- - `url`: 作者主页(可选)
-
-### 许可和URL
-- `license`: 插件许可证(可选,建议填写)
-- `homepage_url`: 插件主页(可选)
-- `repository_url`: 源码仓库地址(可选)
-
-### 分类和标签
-- `keywords`: 关键词数组(可选,建议填写)
-- `categories`: 分类数组(可选,建议填写)
-
-### 兼容性
-- `host_application`: 主机应用兼容性(可选,建议填写)
- - `min_version`: 最低兼容版本
- - `max_version`: 最高兼容版本
-
-⚠️ 在不填写的情况下,插件将默认支持所有版本。**(由于我们在不同版本对插件系统进行了大量的重构,这种情况几乎不可能。)**
-
-### 国际化
-- `default_locale`: 默认语言(可选)
-- `locales_path`: 语言文件目录(可选)
-
-### 插件特定信息
-- `plugin_info`: 插件详细信息(可选)
- - `is_built_in`: 是否为内置插件
- - `plugin_type`: 插件类型
- - `components`: 组件列表
-
-## ⚠️ 注意事项
-
-1. **强制要求**:所有插件必须包含`_manifest.json`文件,否则无法加载
-2. **编码格式**:manifest文件必须使用UTF-8编码
-3. **JSON格式**:文件必须是有效的JSON格式
-4. **必需字段**:`manifest_version`、`name`、`version`、`description`、`author.name`是必需的
-5. **版本兼容**:当前只支持`manifest_version = 1`
-
-## 🔍 常见问题
-
-### Q: 可以不填写可选字段吗?
-A: 可以。所有标记为"可选"的字段都可以不填写,但建议至少填写`license`和`keywords`。
-
-### Q: manifest验证失败怎么办?
-A: 根据验证器的错误提示修复相应问题。错误会导致插件加载失败,警告不会。
-
-## 📚 参考示例
-
-查看内置插件的manifest文件作为参考:
-- `src/plugins/built_in/core_actions/_manifest.json`
-- `src/plugins/built_in/tts_plugin/_manifest.json`
-- `src/plugins/hello_world_plugin/_manifest.json`
diff --git a/docs-src/plugins/quick-start.md b/docs-src/plugins/quick-start.md
deleted file mode 100644
index 48eff603..00000000
--- a/docs-src/plugins/quick-start.md
+++ /dev/null
@@ -1,428 +0,0 @@
-# 🚀 快速开始指南
-
-本指南将带你从零开始创建一个功能完整的MaiCore插件。
-
-## 📖 概述
-
-这个指南将带你快速创建你的第一个MaiCore插件。我们将创建一个简单的问候插件,展示插件系统的基本概念。
-
-以下代码都在我们的`plugins/hello_world_plugin/`目录下。
-
-### 一个方便的小设计
-
-在开发中,我们在`__init__.py`中定义了一个`__all__`变量,包含了所有需要导出的类和函数。
-这样在其他地方导入时,可以直接使用 `from src.plugin_system import *` 来导入所有插件相关的类和函数。
-或者你可以直接使用 `from src.plugin_system import BasePlugin, register_plugin, ComponentInfo` 之类的方式来导入你需要的部分。
-
-### 📂 准备工作
-
-确保你已经:
-
-1. 克隆了MaiCore项目
-2. 安装了Python依赖
-3. 了解基本的Python语法
-
-## 🏗️ 创建插件
-
-### 1. 创建插件目录
-
-在项目根目录的 `plugins/` 文件夹下创建你的插件目录
-
-这里我们创建一个名为 `hello_world_plugin` 的目录
-
-### 2. 创建`_manifest.json`文件
-
-在插件目录下面创建一个 `_manifest.json` 文件,内容如下:
-
-```json
-{
- "manifest_version": 1,
- "name": "Hello World 插件",
- "version": "1.0.0",
- "description": "一个简单的 Hello World 插件",
- "author": {
- "name": "你的名字"
- }
-}
-```
-
-有关 `_manifest.json` 的详细说明,请参考 [Manifest文件指南](./manifest-guide.md)。
-
-### 3. 创建最简单的插件
-
-让我们从最基础的开始!创建 `plugin.py` 文件:
-
-```python
-from typing import List, Tuple, Type
-from src.plugin_system import BasePlugin, register_plugin, ComponentInfo
-
-@register_plugin # 注册插件
-class HelloWorldPlugin(BasePlugin):
- """Hello World插件 - 你的第一个MaiCore插件"""
-
- # 以下是插件基本信息和方法(必须填写)
- plugin_name = "hello_world_plugin"
- enable_plugin = True # 启用插件
- dependencies = [] # 插件依赖列表(目前为空)
- python_dependencies = [] # Python依赖列表(目前为空)
- config_file_name = "config.toml" # 配置文件名
- config_schema = {} # 配置文件模式(目前为空)
-
- def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: # 获取插件组件
- """返回插件包含的组件列表(目前是空的)"""
- return []
-```
-
-🎉 恭喜!你刚刚创建了一个最简单但完整的MaiCore插件!
-
-**解释一下这些代码:**
-
-- 首先,我们在`plugin.py`中定义了一个HelloWorldPlugin插件类,继承自 `BasePlugin` ,提供基本功能。
-- 通过给类加上,`@register_plugin` 装饰器,我们告诉系统"这是一个插件"
-- `plugin_name` 等是插件的基本信息,必须填写
-- `get_plugin_components()` 返回插件的功能组件,现在我们没有定义任何 Action, Command 或者 EventHandler,所以返回空列表。
-
-### 4. 测试基础插件
-
-现在就可以测试这个插件了!启动MaiCore:
-
-直接通过启动器运行MaiCore或者 `python bot.py`
-
-在日志中你应该能看到插件被加载的信息。虽然插件还没有任何功能,但它已经成功运行了!
-
-
-
-### 5. 添加第一个功能:问候Action
-
-现在我们要给插件加入一个有用的功能,我们从最好玩的Action做起
-
-Action是一类可以让MaiCore根据自身意愿选择使用的“动作”,在MaiCore中,不论是“回复”还是“不回复”,或者“发送表情”以及“禁言”等等,都是通过Action实现的。
-
-你可以通过编写动作,来拓展MaiCore的能力,包括发送语音,截图,甚至操作文件,编写代码......
-
-现在让我们给插件添加第一个简单的功能。这个Action可以对用户发送一句问候语。
-
-在 `plugin.py` 文件中添加Action组件,完整代码如下:
-
-```python
-from typing import List, Tuple, Type
-from src.plugin_system import (
- BasePlugin, register_plugin, BaseAction,
- ComponentInfo, ActionActivationType, ChatMode
-)
-
-# ===== Action组件 =====
-
-class HelloAction(BaseAction):
- """问候Action - 简单的问候动作"""
-
- # === 基本信息(必须填写)===
- action_name = "hello_greeting"
- action_description = "向用户发送问候消息"
- activation_type = ActionActivationType.ALWAYS # 始终激活
-
- # === 功能描述(必须填写)===
- action_parameters = {"greeting_message": "要发送的问候消息"}
- action_require = ["需要发送友好问候时使用", "当有人向你问好时使用", "当你遇见没有见过的人时使用"]
- associated_types = ["text"]
-
- async def execute(self) -> Tuple[bool, str]:
- """执行问候动作 - 这是核心功能"""
- # 发送问候消息
- greeting_message = self.action_data.get("greeting_message", "")
- base_message = self.get_config("greeting.message", "嗨!很开心见到你!😊")
- message = base_message + greeting_message
- await self.send_text(message)
-
- return True, "发送了问候消息"
-
-@register_plugin
-class HelloWorldPlugin(BasePlugin):
- """Hello World插件 - 你的第一个MaiCore插件"""
-
- # 插件基本信息
- plugin_name = "hello_world_plugin"
- enable_plugin = True
- dependencies = []
- python_dependencies = []
- config_file_name = "config.toml"
- config_schema = {}
-
- def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
- """返回插件包含的组件列表"""
- return [
- # 添加我们的问候Action
- (HelloAction.get_action_info(), HelloAction),
- ]
-```
-
-**解释一下这些代码:**
-
-- `HelloAction` 是我们定义的问候动作类,继承自 `BaseAction`,并实现了核心功能。
-- 在 `HelloWorldPlugin` 中,我们通过 `get_plugin_components()` 方法,通过调用`get_action_info()`这个内置方法将 `HelloAction` 注册为插件的一个组件。
-- 这样一来,当插件被加载时,问候动作也会被一并加载,并可以在MaiCore中使用。
-- `execute()` 函数是Action的核心,定义了当Action被MaiCore选择后,具体要做什么
-- `self.send_text()` 是发送文本消息的便捷方法
-
-Action 组件中有关`activation_type`、`action_parameters`、`action_require`、`associated_types` 等的详细说明请参考 [Action组件指南](./action-components.md)。
-
-### 6. 测试问候Action
-
-重启MaiCore,然后在聊天中发送任意消息,比如:
-
-```
-你好
-```
-
-MaiCore可能会选择使用你的问候Action,发送回复:
-
-```
-嗨!很开心见到你!😊
-```
-
-
-
-> **💡 小提示**:MaiCore会智能地决定什么时候使用它。如果没有立即看到效果,多试几次不同的消息。
-
-🎉 太棒了!你的插件已经有实际功能了!
-
-### 7. 添加第二个功能:时间查询Command
-
-现在让我们添加一个Command组件。Command和Action不同,它是直接响应用户命令的:
-
-Command是最简单,最直接的响应,不由LLM判断选择使用
-
-```python
-# 在现有代码基础上,添加Command组件
-import datetime
-from src.plugin_system import BaseCommand
-#导入Command基类
-
-class TimeCommand(BaseCommand):
- """时间查询Command - 响应/time命令"""
-
- command_name = "time"
- command_description = "查询当前时间"
-
- # === 命令设置(必须填写)===
- command_pattern = r"^/time$" # 精确匹配 "/time" 命令
-
- async def execute(self) -> Tuple[bool, Optional[str], bool]:
- """执行时间查询"""
- # 获取当前时间
- 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)
-
- return True, f"显示了当前时间: {time_str}", True
-
-@register_plugin
-class HelloWorldPlugin(BasePlugin):
- """Hello World插件 - 你的第一个MaiCore插件"""
-
- # 插件基本信息
- plugin_name = "hello_world_plugin"
- enable_plugin = True
- dependencies = []
- python_dependencies = []
- config_file_name = "config.toml"
- config_schema = {}
-
- def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
- return [
- (HelloAction.get_action_info(), HelloAction),
- (TimeCommand.get_command_info(), TimeCommand),
- ]
-```
-
-同样的,我们通过 `get_plugin_components()` 方法,通过调用`get_action_info()`这个内置方法将 `TimeCommand` 注册为插件的一个组件。
-
-**Command组件解释:**
-
-- `command_pattern` 使用正则表达式匹配用户输入
-- `^/time$` 表示精确匹配 "/time"
-
-有关 Command 组件的更多信息,请参考 [Command组件指南](./command-components.md)。
-
-### 8. 测试时间查询Command
-
-重启MaiCore,发送命令:
-
-```
-/time
-```
-
-你应该会收到回复:
-
-```
-⏰ 当前时间:2024-01-01 12:00:00
-```
-
-🎉 太棒了!现在你已经了解了基本的 Action 和 Command 组件的使用方法。你可以根据自己的需求,继续扩展插件的功能,添加更多的 Action 和 Command 组件,让你的插件更加丰富和强大!
-
----
-
-## 进阶教程
-
-如果你想让插件更加灵活和强大,可以参考接下来的进阶教程。
-
-### 1. 添加配置文件
-
-想要为插件添加配置文件吗?让我们一起来配置`config_schema`属性!
-
-> **🚨 重要:不要手动创建config.toml文件!**
->
-> 我们需要在插件代码中定义配置Schema,让系统自动生成配置文件。
-
-首先,在插件类中定义配置Schema:
-
-```python
-from src.plugin_system import ConfigField
-
-@register_plugin
-class HelloWorldPlugin(BasePlugin):
- """Hello World插件 - 你的第一个MaiCore插件"""
-
- # 插件基本信息
- plugin_name: str = "hello_world_plugin" # 内部标识符
- enable_plugin: bool = True
- dependencies: List[str] = [] # 插件依赖列表
- python_dependencies: List[str] = [] # Python包依赖列表
- config_file_name: str = "config.toml" # 配置文件名
-
- # 配置Schema定义
- config_schema: dict = {
- "plugin": {
- "name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"),
- "version": ConfigField(type=str, default="1.0.0", description="插件版本"),
- "enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
- },
- "greeting": {
- "message": ConfigField(type=str, default="嗨!很开心见到你!😊", description="默认问候消息"),
- "enable_emoji": ConfigField(type=bool, default=True, description="是否启用表情符号"),
- },
- "time": {"format": ConfigField(type=str, default="%Y-%m-%d %H:%M:%S", description="时间显示格式")},
- }
-
- def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
- return [
- (HelloAction.get_action_info(), HelloAction),
- (TimeCommand.get_command_info(), TimeCommand),
- ]
-```
-
-这会生成一个如下的 `config.toml` 文件:
-
-```toml
-# hello_world_plugin - 自动生成的配置文件
-# 我的第一个MaiCore插件,包含问候功能和时间查询等基础示例
-
-# 插件基本信息
-[plugin]
-
-# 插件名称
-name = "hello_world_plugin"
-
-# 插件版本
-version = "1.0.0"
-
-# 是否启用插件
-enabled = false
-
-
-# 问候功能配置
-[greeting]
-
-# 默认问候消息
-message = "嗨!很开心见到你!😊"
-
-# 是否启用表情符号
-enable_emoji = true
-
-
-# 时间查询配置
-[time]
-
-# 时间显示格式
-format = "%Y-%m-%d %H:%M:%S"
-```
-
-然后修改Action和Command代码,通过 `get_config()` 方法让它们读取配置(配置的键是命名空间式的):
-
-```python
-class HelloAction(BaseAction):
- """问候Action - 简单的问候动作"""
-
- # === 基本信息(必须填写)===
- action_name = "hello_greeting"
- action_description = "向用户发送问候消息"
- activation_type = ActionActivationType.ALWAYS # 始终激活
-
- # === 功能描述(必须填写)===
- action_parameters = {"greeting_message": "要发送的问候消息"}
- action_require = ["需要发送友好问候时使用", "当有人向你问好时使用", "当你遇见没有见过的人时使用"]
- associated_types = ["text"]
-
- async def execute(self) -> Tuple[bool, str]:
- """执行问候动作 - 这是核心功能"""
- # 发送问候消息
- greeting_message = self.action_data.get("greeting_message", "")
- base_message = self.get_config("greeting.message", "嗨!很开心见到你!😊")
- message = base_message + greeting_message
- await self.send_text(message)
-
- return True, "发送了问候消息"
-
-class TimeCommand(BaseCommand):
- """时间查询Command - 响应/time命令"""
-
- command_name = "time"
- command_description = "查询当前时间"
-
- # === 命令设置(必须填写)===
- command_pattern = r"^/time$" # 精确匹配 "/time" 命令
-
- async def execute(self) -> Tuple[bool, str, bool]:
- """执行时间查询"""
- 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)
-
- return True, f"显示了当前时间: {time_str}", True
-```
-
-**配置系统工作流程:**
-
-1. **定义Schema**: 在插件代码中定义配置结构
-2. **自动生成**: 启动插件时,系统会自动生成 `config.toml` 文件
-3. **用户修改**: 用户可以修改生成的配置文件
-4. **代码读取**: 使用 `self.get_config()` 读取配置值
-
-**绝对不要手动创建 `config.toml` 文件!**
-
-更详细的配置系统介绍请参考 [配置指南](./configuration-guide.md)。
-
-### 2. 创建说明文档
-
-你可以创建一个 `README.md` 文件,描述插件的功能和使用方法。
-
-### 3. 发布到插件市场
-
-如果你想让更多人使用你的插件,可以将它发布到MaiCore的插件市场。
-
-这部分请参考 [plugin-repo](https://github.com/Maim-with-u/plugin-repo) 的文档。
-
----
-
-🎉 恭喜你!你已经成功的创建了自己的插件了!
diff --git a/docs-src/plugins/tool-components.md b/docs-src/plugins/tool-components.md
deleted file mode 100644
index b9dc3570..00000000
--- a/docs-src/plugins/tool-components.md
+++ /dev/null
@@ -1,246 +0,0 @@
-# 🔧 工具组件详解
-
-## 📖 什么是工具
-
-工具是MaiBot的信息获取能力扩展组件。如果说Action组件功能五花八门,可以拓展麦麦能做的事情,那么Tool就是在某个过程中拓宽了麦麦能够获得的信息量。
-
-### 🎯 工具的特点
-
-- 🔍 **信息获取增强**:扩展麦麦获取外部信息的能力
-- 📊 **数据丰富**:帮助麦麦获得更多背景信息和实时数据
-- 🔌 **插件式架构**:支持独立开发和注册新工具
-- ⚡ **自动发现**:工具会被系统自动识别和注册
-
-### 🆚 Tool vs Action vs Command 区别
-
-| 特征 | Action | Command | Tool |
-|-----|-------|---------|------|
-| **主要用途** | 扩展麦麦行为能力 | 响应用户指令 | 扩展麦麦信息获取 |
-| **触发方式** | 麦麦智能决策 | 用户主动触发 | LLM根据需要调用 |
-| **目标** | 让麦麦做更多事情 | 提供具体功能 | 让麦麦知道更多信息 |
-| **使用场景** | 增强交互体验 | 功能服务 | 信息查询和分析 |
-
-## 🏗️ Tool组件的基本结构
-
-每个工具必须继承 `BaseTool` 基类并实现以下属性和方法:
-```python
-from src.plugin_system import BaseTool, ToolParamType
-
-class MyTool(BaseTool):
- # 工具名称,必须唯一
- name = "my_tool"
-
- # 工具描述,告诉LLM这个工具的用途
- description = "这个工具用于获取特定类型的信息"
-
- # 参数定义,仅定义参数
- # 比如想要定义一个类似下面的openai格式的参数表,则可以这么定义:
- # {
- # "type": "object",
- # "properties": {
- # "query": {
- # "type": "string",
- # "description": "查询参数"
- # },
- # "limit": {
- # "type": "integer",
- # "description": "结果数量限制"
- # "enum": [10, 20, 50] # 可选值
- # }
- # },
- # "required": ["query"]
- # }
- parameters = [
- ("query", ToolParamType.STRING, "查询参数", True, None), # 必填参数
- ("limit", ToolParamType.INTEGER, "结果数量限制", False, ["10", "20", "50"]) # 可选参数
- ]
-
- available_for_llm = True # 是否对LLM可用
-
- async def execute(self, function_args: Dict[str, Any]):
- """执行工具逻辑"""
- # 实现工具功能
- result = f"查询结果: {function_args.get('query')}"
-
- return {
- "name": self.name,
- "content": result
- }
-```
-
-### 属性说明
-
-| 属性 | 类型 | 说明 |
-|-----|------|------|
-| `name` | str | 工具的唯一标识名称 |
-| `description` | str | 工具功能描述,帮助LLM理解用途 |
-| `parameters` | list[tuple] | 参数定义 |
-
-其构造而成的工具定义为:
-```python
-definition: Dict[str, Any] = {"name": cls.name, "description": cls.description, "parameters": cls.parameters}
-```
-
-### 方法说明
-
-| 方法 | 参数 | 返回值 | 说明 |
-|-----|------|--------|------|
-| `execute` | `function_args` | `dict` | 执行工具核心逻辑 |
-
----
-
-## 🎨 完整工具示例
-
-完成一个天气查询工具
-
-```python
-from src.plugin_system import BaseTool
-import aiohttp
-import json
-
-class WeatherTool(BaseTool):
- """天气查询工具 - 获取指定城市的实时天气信息"""
-
- name = "weather_query"
- description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况等"
- available_for_llm = True # 允许LLM调用此工具
- parameters = [
- ("city", ToolParamType.STRING, "要查询天气的城市名称,如:北京、上海、纽约", True, None),
- ("country", ToolParamType.STRING, "国家代码,如:CN、US,可选参数", False, None)
- ]
-
- async def execute(self, function_args: dict):
- """执行天气查询"""
- try:
- city = function_args.get("city")
- country = function_args.get("country", "")
-
- # 构建查询参数
- location = f"{city},{country}" if country else city
-
- # 调用天气API(示例)
- weather_data = await self._fetch_weather(location)
-
- # 格式化结果
- result = self._format_weather_data(weather_data)
-
- return {
- "name": self.name,
- "content": result
- }
-
- except Exception as e:
- return {
- "name": self.name,
- "content": f"天气查询失败: {str(e)}"
- }
-
- async def _fetch_weather(self, location: str) -> dict:
- """获取天气数据"""
- # 这里是示例,实际需要接入真实的天气API
- api_url = f"http://api.weather.com/v1/current?q={location}"
-
- async with aiohttp.ClientSession() as session:
- async with session.get(api_url) as response:
- return await response.json()
-
- def _format_weather_data(self, data: dict) -> str:
- """格式化天气数据"""
- if not data:
- return "暂无天气数据"
-
- # 提取关键信息
- city = data.get("location", {}).get("name", "未知城市")
- temp = data.get("current", {}).get("temp_c", "未知")
- condition = data.get("current", {}).get("condition", {}).get("text", "未知")
- humidity = data.get("current", {}).get("humidity", "未知")
-
- # 格式化输出
- return f"""
-🌤️ {city} 实时天气
-━━━━━━━━━━━━━━━━━━
-🌡️ 温度: {temp}°C
-☁️ 天气: {condition}
-💧 湿度: {humidity}%
-━━━━━━━━━━━━━━━━━━
- """.strip()
-```
-
----
-
-## 🚨 注意事项和限制
-
-### 当前限制
-
-1. **适用范围**:主要适用于信息获取场景
-2. **配置要求**:必须开启工具处理器
-
-### 开发建议
-
-1. **功能专一**:每个工具专注单一功能
-2. **参数明确**:清晰定义工具参数和用途
-3. **错误处理**:完善的异常处理和错误反馈
-4. **性能考虑**:避免长时间阻塞操作
-5. **信息准确**:确保获取信息的准确性和时效性
-
-## 🎯 最佳实践
-
-### 1. 工具命名规范
-#### ✅ 好的命名
-```python
-name = "weather_query" # 清晰表达功能
-name = "knowledge_search" # 描述性强
-name = "stock_price_check" # 功能明确
-```
-#### ❌ 避免的命名
-```python
-name = "tool1" # 无意义
-name = "wq" # 过于简短
-name = "weather_and_news" # 功能过于复杂
-```
-
-### 2. 描述规范
-#### ✅ 良好的描述
-```python
-description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况"
-```
-#### ❌ 避免的描述
-```python
-description = "天气" # 过于简单
-description = "获取信息" # 不够具体
-```
-
-### 3. 参数设计
-
-#### ✅ 合理的参数设计
-```python
-parameters = [
- ("city", ToolParamType.STRING, "城市名称,如:北京、上海", True, None),
- ("unit", ToolParamType.STRING, "温度单位:celsius 或 fahrenheit", False, ["celsius", "fahrenheit"])
-]
-```
-#### ❌ 避免的参数设计
-```python
-parameters = [
- ("data", "string", "数据", True) # 参数过于模糊
-]
-```
-
-### 4. 结果格式化
-#### ✅ 良好的结果格式
-```python
-def _format_result(self, data):
- return f"""
-🔍 查询结果
-━━━━━━━━━━━━
-📊 数据: {data['value']}
-📅 时间: {data['timestamp']}
-📝 说明: {data['description']}
-━━━━━━━━━━━━
- """.strip()
-```
-#### ❌ 避免的结果格式
-```python
-def _format_result(self, data):
- return str(data) # 直接返回原始数据
-```
diff --git a/docs-src/CONTRIBUTE.md b/docs/CONTRIBUTE.md
similarity index 100%
rename from docs-src/CONTRIBUTE.md
rename to docs/CONTRIBUTE.md
diff --git a/saka.py b/saka.py
index 5d17870b..880ab0fd 100644
--- a/saka.py
+++ b/saka.py
@@ -10,21 +10,19 @@ MaiSaka - 程序入口
ENABLE_THINKING - 是否启用思考模式 (可选, true/false, 不设置则不发送该参数)
"""
-import asyncio
-import sys
from pathlib import Path
-# 添加项目根目录和 src/maisaka 到 Python 路径
+import asyncio
+import sys
+
+# 添加项目根目录到 Python 路径
_root = Path(__file__).parent
-_maisaka_path = _root / "src" / "maisaka"
if str(_root) not in sys.path:
sys.path.insert(0, str(_root))
-if str(_maisaka_path) not in sys.path:
- sys.path.insert(0, str(_maisaka_path))
+from src.cli.console import console # noqa: E402
+from src.cli.maisaka_cli import BufferCLI # noqa: E402
from src.prompt.prompt_manager import prompt_manager # noqa: E402
-from src.maisaka.cli import BufferCLI # noqa: E402
-from src.maisaka.config import console # noqa: E402
def main():
diff --git a/src/chat/image_system/image_manager.py b/src/chat/image_system/image_manager.py
index 4ab7dbf5..d30cb8ae 100644
--- a/src/chat/image_system/image_manager.py
+++ b/src/chat/image_system/image_manager.py
@@ -14,7 +14,6 @@ from src.common.database.database import get_db_session
from src.common.database.database_model import Images, ImageType
from src.common.data_models.image_data_model import MaiImage
from src.config.config import global_config
-from src.common.data_models.llm_service_data_models import LLMImageOptions
from src.services.llm_service import LLMServiceClient
install(extra_lines=3)
@@ -382,7 +381,6 @@ class ImageManager:
prompt,
image_base64,
image_format,
- options=LLMImageOptions(temperature=0.4),
)
description = generation_result.response
if not description:
diff --git a/src/config/legacy_migration.py b/src/config/legacy_migration.py
index e7d9f85c..eae7366b 100644
--- a/src/config/legacy_migration.py
+++ b/src/config/legacy_migration.py
@@ -170,6 +170,38 @@ def _migrate_expression_learning_list(expr: dict[str, Any]) -> bool:
return True
+def _migrate_chat_talk_value_rules(chat: dict[str, Any]) -> bool:
+ """
+ 将旧版 target 字段迁移为当前运行时使用的 platform/item_id/rule_type 结构。
+ """
+ talk_value_rules = _as_list(chat.get("talk_value_rules"))
+ if talk_value_rules is None:
+ return False
+
+ migrated = False
+ for rule in talk_value_rules:
+ rule_item = _as_dict(rule)
+ if rule_item is None or "target" not in rule_item:
+ continue
+
+ target_raw = rule_item.get("target")
+ target = "" if target_raw is None else str(target_raw).strip()
+ if not target:
+ parsed = {"platform": "", "item_id": "", "rule_type": "group"}
+ else:
+ parsed = _parse_triplet_target(target)
+ if parsed is None:
+ continue
+
+ rule_item["platform"] = parsed["platform"]
+ rule_item["item_id"] = parsed["item_id"]
+ rule_item["rule_type"] = parsed["rule_type"]
+ rule_item.pop("target", None)
+ migrated = True
+
+ return migrated
+
+
def _migrate_expression_groups(expr: dict[str, Any]) -> bool:
"""
将旧版 expression.expression_groups 转成当前结构。
@@ -316,6 +348,11 @@ def try_migrate_legacy_bot_config_dict(data: dict[str, Any]) -> MigrationResult:
migrated_any = True
reasons.append("bot.qq_account_empty")
+ chat = _as_dict(data.get("chat"))
+ if chat is not None and _migrate_chat_talk_value_rules(chat):
+ migrated_any = True
+ reasons.append("chat.talk_value_rules_target")
+
expr = _as_dict(data.get("expression"))
if expr is not None:
if _migrate_expression_learning_list(expr):
diff --git a/src/emoji_system/emoji_manager.py b/src/emoji_system/emoji_manager.py
index ac31ea3a..f3d6d879 100644
--- a/src/emoji_system/emoji_manager.py
+++ b/src/emoji_system/emoji_manager.py
@@ -14,7 +14,7 @@ from sqlmodel import select
import Levenshtein
from src.common.data_models.image_data_model import MaiEmoji
-from src.common.data_models.llm_service_data_models import LLMGenerationOptions, LLMImageOptions
+from src.common.data_models.llm_service_data_models import LLMGenerationOptions
from src.common.database.database import get_db_session, get_db_session_manual
from src.common.database.database_model import Images, ImageType
from src.common.logger import get_logger
@@ -778,7 +778,7 @@ class EmojiManager:
decision_result = await emoji_manager_emotion_judge_llm.generate_response(
emoji_replace_prompt,
- options=LLMGenerationOptions(temperature=0.8, max_tokens=600),
+ options=LLMGenerationOptions(max_tokens=600),
)
decision = decision_result.response
logger.info(f"[决策] 结果: {decision}")
@@ -853,7 +853,6 @@ class EmojiManager:
prompt,
image_base64,
"jpg",
- options=LLMImageOptions(temperature=0.5),
)
description = description_result.response
else:
@@ -865,7 +864,6 @@ class EmojiManager:
prompt,
image_base64,
image_format,
- options=LLMImageOptions(temperature=0.5),
)
description = description_result.response
except Exception as e:
@@ -886,7 +884,6 @@ class EmojiManager:
filtration_prompt,
image_base64,
image_format,
- options=LLMImageOptions(temperature=0.3),
)
llm_response = filtration_result.response
except Exception as e:
diff --git a/src/emoji_system/maisaka_tool.py b/src/emoji_system/maisaka_tool.py
index d9a9cca7..75c0bb19 100644
--- a/src/emoji_system/maisaka_tool.py
+++ b/src/emoji_system/maisaka_tool.py
@@ -9,7 +9,6 @@ import random
from src.chat.message_receive.chat_manager import chat_manager
from src.cli.maisaka_cli_sender import CLI_PLATFORM_NAME, render_cli_message
from src.common.data_models.image_data_model import MaiEmoji
-from src.common.data_models.llm_service_data_models import LLMGenerationOptions
from src.common.logger import get_logger
from src.common.utils.utils_image import ImageUtils
from src.services import send_service
@@ -18,7 +17,6 @@ from .emoji_manager import (
_normalize_emoji_tag_text,
_serialize_emoji_for_hook,
emoji_manager,
- emoji_manager_emotion_judge_llm,
)
logger = get_logger("emoji_maisaka_tool")
@@ -123,56 +121,6 @@ def _normalize_emotions(emoji: MaiEmoji) -> list[str]:
return []
-def _build_recent_context_text(context_texts: Sequence[str], max_items: int = 5) -> str:
- """构建供情绪判断使用的最近上下文文本。"""
-
- normalized_items = [str(item).strip() for item in context_texts if str(item).strip()]
- if not normalized_items:
- return ""
- return "\n".join(normalized_items[-max_items:])
-
-
-async def _select_emoji_with_llm(
- *,
- sampled_emojis: Sequence[MaiEmoji],
- reasoning: str,
- context_text: str,
-) -> tuple[MaiEmoji, str]:
- """让模型在采样表情中选择更合适的情绪标签。"""
-
- emotion_map: dict[str, list[MaiEmoji]] = {}
- for emoji in sampled_emojis:
- for emotion in _normalize_emotions(emoji):
- emotion_map.setdefault(emotion, []).append(emoji)
-
- available_emotions = list(emotion_map.keys())
- if not available_emotions:
- return random.choice(list(sampled_emojis)), ""
-
- prompt = (
- "你正在为聊天场景选择一个最合适的表情包情绪标签。\n"
- f"发送原因:{reasoning or '辅助表达当前语气和情绪'}\n"
- f"最近聊天记录:\n{context_text or '(暂无额外上下文)'}\n\n"
- "可选情绪标签如下:\n"
- f"{chr(10).join(available_emotions)}\n\n"
- "请只返回一个最匹配的情绪标签,不要解释。"
- )
-
- try:
- llm_result = await emoji_manager_emotion_judge_llm.generate_response(
- prompt,
- options=LLMGenerationOptions(temperature=0.3, max_tokens=60),
- )
- chosen_emotion = (llm_result.response or "").strip().strip("\"'")
- except Exception as exc:
- logger.warning(f"使用 LLM 选择表情情绪失败,将回退为随机选择: {exc}")
- chosen_emotion = ""
-
- if chosen_emotion and chosen_emotion in emotion_map:
- return random.choice(emotion_map[chosen_emotion]), chosen_emotion
- return random.choice(list(sampled_emojis)), ""
-
-
async def select_emoji_for_maisaka(
*,
requested_emotion: str = "",
@@ -182,6 +130,8 @@ async def select_emoji_for_maisaka(
) -> tuple[MaiEmoji | None, str]:
"""为 Maisaka 选择一个合适的表情。"""
+ del reasoning, context_texts
+
available_emojis = list(emoji_manager.emojis)
if not available_emojis:
return None, ""
@@ -200,12 +150,7 @@ async def select_emoji_for_maisaka(
available_emojis,
min(max(sample_size, 1), len(available_emojis)),
)
- context_text = _build_recent_context_text(context_texts or [])
- return await _select_emoji_with_llm(
- sampled_emojis=sampled_emojis,
- reasoning=reasoning,
- context_text=context_text,
- )
+ return random.choice(sampled_emojis), ""
async def send_emoji_for_maisaka(
diff --git a/src/maisaka/builtin_tool/reply.py b/src/maisaka/builtin_tool/reply.py
index f03d9d2c..eb5cdf46 100644
--- a/src/maisaka/builtin_tool/reply.py
+++ b/src/maisaka/builtin_tool/reply.py
@@ -24,7 +24,6 @@ async def _run_expression_selector(tool_ctx: BuiltinToolRuntimeContext, system_p
system_prompt=system_prompt,
request_kind="expression_selector",
max_tokens=256,
- temperature=0.1,
)
return (response.content or "").strip()
diff --git a/src/maisaka/chat_loop_service.py b/src/maisaka/chat_loop_service.py
index 377eee9c..e14dd0c0 100644
--- a/src/maisaka/chat_loop_service.py
+++ b/src/maisaka/chat_loop_service.py
@@ -187,7 +187,6 @@ class MaisakaChatLoopService:
chat_system_prompt: Optional[str] = None,
session_id: Optional[str] = None,
is_group_chat: Optional[bool] = None,
- temperature: float = 0.5,
max_tokens: int = 2048,
) -> None:
"""初始化 Maisaka 对话循环服务。
@@ -196,11 +195,9 @@ class MaisakaChatLoopService:
chat_system_prompt: 可选的系统提示词。
session_id: 当前会话 ID,用于匹配会话级额外提示。
is_group_chat: 当前会话是否为群聊。
- temperature: 规划器温度参数。
max_tokens: 规划器最大输出长度。
"""
- self._temperature = temperature
self._max_tokens = max_tokens
self._is_group_chat = is_group_chat
self._session_id = session_id or ""
@@ -546,7 +543,6 @@ class MaisakaChatLoopService:
message_factory=message_factory,
options=LLMGenerationOptions(
tool_options=all_tools if all_tools else None,
- temperature=self._temperature,
max_tokens=self._max_tokens,
response_format=response_format,
interrupt_flag=self._interrupt_flag,
diff --git a/src/maisaka/reasoning_engine.py b/src/maisaka/reasoning_engine.py
index a155eb3c..603ee2a3 100644
--- a/src/maisaka/reasoning_engine.py
+++ b/src/maisaka/reasoning_engine.py
@@ -138,7 +138,6 @@ class MaisakaReasoningEngine:
request_kind="timing_gate",
interrupt_flag=None,
max_tokens=TIMING_GATE_MAX_TOKENS,
- temperature=0.1,
tool_definitions=tool_definitions,
)
diff --git a/src/maisaka/runtime.py b/src/maisaka/runtime.py
index 6ae6cb66..c595a537 100644
--- a/src/maisaka/runtime.py
+++ b/src/maisaka/runtime.py
@@ -566,7 +566,6 @@ class MaisakaHeartFlowChatting:
interrupt_flag: asyncio.Event | None = None,
max_tokens: int = 512,
response_format: RespFormat | None = None,
- temperature: float = 0.2,
tool_definitions: Optional[Sequence[ToolDefinitionInput]] = None,
) -> ChatResponse:
"""运行一个复制上下文的临时子代理,并在完成后立即销毁。"""
@@ -584,7 +583,6 @@ class MaisakaHeartFlowChatting:
chat_system_prompt=system_prompt,
session_id=self.session_id,
is_group_chat=self.chat_stream.is_group_session,
- temperature=temperature,
max_tokens=max_tokens,
)
sub_agent.set_interrupt_flag(interrupt_flag)
@@ -611,7 +609,6 @@ class MaisakaHeartFlowChatting:
request_kind="reply_effect_judge",
extra_messages=[judge_message],
max_tokens=900,
- temperature=0.1,
tool_definitions=[],
)
return (response.content or "").strip()