What happened / 发生了什么
turn_off_plugin 将工具名写入持久化黑名单 inactivated_llm_tools(SQLite preferences 表),但恢复路径仅有一条:在 WebUI 中手动点击「启用插件」按钮。AstrBot 正常重启(stop() → load())、reload()、restart() 均不经过 turn_on_plugin,导致黑名单条目随每次停用操作不断累积,重启后无差别将所有工具设为关闭状态。
根因:写入和恢复路径不对称
下面是 inactivated_llm_tools 的完整数据流:
┌──────────────────────────────────────────────────┐
│ 写入(唯一路径) │
│ star_manager.py:1712-1716 — turn_off_plugin │
│ sp.global_put("inactivated_llm_tools", [...]) │
│ → 持久化到 SQLite preferences 表 │
├──────────────────────────────────────────────────┤
│ 读取 + 应用 │
│ star_manager.py:891 — load() │
│ inactivated_llm_tools = sp.global_get(...) │
│ star_manager.py:1091 — load() │
│ if ft.name in inactivated_llm_tools: │
│ ft.active = False │
│ (只应用黑名单,从不清理) │
├──────────────────────────────────────────────────┤
│ 恢复(唯一路径) │
│ dashboard/routes/plugin.py:1902 │
│ → turn_on_plugin │
│ → 遍历 func_list,清理匹配的条目 │
│ → 仅 WebUI 手动「启用插件」触发 │
└──────────────────────────────────────────────────┘
关键缺口在 load():它读取黑名单、应用黑名单,但从不清理那些"对应插件已启用"的条目。load() 在所有插件加载完成后应该检查:某个插件是启用的 → 它的工具不应该在黑名单里 → 清除对应条目。
此外,以下常见操作路径完全绕过了 turn_on_plugin:
| 操作 |
是否调 turn_on_plugin |
AstrBot 重启(stop() → load()) |
❌ |
reload()(_unbind_plugin → _terminate_plugin → load()) |
❌ |
restart() |
❌ |
| WebUI「启用插件」按钮 |
✅(唯一) |
累积效应
每次停用-重新启用循环如果是通过 AstrBot 重启(而非 WebUI 按钮)完成的,就会在 DB 中留下 N 个幽灵条目。多次累积后,inactivated_llm_tools 列表持续增长,load() 在 L1091 无差别应用——即使用户手动逐个打开过所有工具,重启后它们又全被关闭。
涉及文件
| 文件 |
行号 |
说明 |
astrbot/core/star/star_manager.py |
870-1249 |
load():读取并应用黑名单,但缺少末尾清理步骤 |
astrbot/core/star/star_manager.py |
1679-1718 |
turn_off_plugin:唯一写入点 |
astrbot/core/star/star_manager.py |
1767-1791 |
turn_on_plugin:唯一清理点(但不在重启路径中) |
astrbot/dashboard/routes/plugin.py |
1902 |
WebUI 触发 turn_on_plugin 的唯一入口 |
Expected behavior / 期望行为
load() 在所有插件加载完成后,遍历所有 activated=True 的插件已注册的工具,将匹配条目从 inactivated_llm_tools 中清除并恢复 active:
# load() 末尾,所有 star 加载完成后(仅 full reload 时执行)
# 遍历 star_registry 而非 star_map,因为前者按注册顺序保留
for star_meta in star_registry:
if not star_meta.activated or not star_meta.module_path:
continue
plugin_path = star_meta.module_path
for func_tool in llm_tools.func_list:
mp = func_tool.handler_module_path
if not mp:
continue
if mp.startswith(plugin_path):
if func_tool.name in inactivated_llm_tools:
inactivated_llm_tools.remove(func_tool.name)
func_tool.active = True
await sp.global_put("inactivated_llm_tools", inactivated_llm_tools)
注意:此修复仅针对"因插件整体停用而写入黑名单的工具"。由于 inactivated_llm_tools 是扁平列表,不区分"因插件停用而关闭"和"用户单独手动关闭",用户单独关闭的工具也会在重启后被恢复。这是 inactivated_llm_tools 架构层面的缺陷(turn_on_plugin 目前同样有此问题),彻底的修复需要将两套语义分开存储(例如新增 inactivated_plugins 作为独立判断依据),不在本 issue 范围内。
Reproduce / 如何复现?
- 部署一个注册了函数工具的插件
- WebUI 停用该插件 →
turn_off_plugin 将 N 个工具名写入 DB
- WebUI 重新启用插件 → 工具恢复正常(这一步走了
turn_on_plugin,清理成功)
- 重启 AstrBot(不走
turn_on_plugin)→ load() 从 DB 读取黑名单 → 工具被设为 active=False
- 用户手动在「函数工具管理」中重新打开工具
- 再次重启 AstrBot →
load() 再次读取 → 工具再次被关闭
黑名单条目不会被任何重启路径清理,只能通过 WebUI 启用插件来清除。
AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
| 项 |
值 |
| AstrBot 版本 |
v4.24.2 |
| Python 版本 |
3.12.12 |
| 操作系统 |
Windows 11 |
OS
Windows
Logs / 报错日志
无显式报错。
Are you willing to submit a PR? / 你愿意提交 PR 吗?
Code of Conduct
What happened / 发生了什么
turn_off_plugin将工具名写入持久化黑名单inactivated_llm_tools(SQLitepreferences表),但恢复路径仅有一条:在 WebUI 中手动点击「启用插件」按钮。AstrBot 正常重启(stop()→load())、reload()、restart()均不经过turn_on_plugin,导致黑名单条目随每次停用操作不断累积,重启后无差别将所有工具设为关闭状态。根因:写入和恢复路径不对称
下面是
inactivated_llm_tools的完整数据流:关键缺口在
load():它读取黑名单、应用黑名单,但从不清理那些"对应插件已启用"的条目。load()在所有插件加载完成后应该检查:某个插件是启用的 → 它的工具不应该在黑名单里 → 清除对应条目。此外,以下常见操作路径完全绕过了
turn_on_plugin:turn_on_pluginstop()→load())reload()(_unbind_plugin→_terminate_plugin→load())restart()累积效应
每次停用-重新启用循环如果是通过 AstrBot 重启(而非 WebUI 按钮)完成的,就会在 DB 中留下 N 个幽灵条目。多次累积后,
inactivated_llm_tools列表持续增长,load()在 L1091 无差别应用——即使用户手动逐个打开过所有工具,重启后它们又全被关闭。涉及文件
astrbot/core/star/star_manager.pyload():读取并应用黑名单,但缺少末尾清理步骤astrbot/core/star/star_manager.pyturn_off_plugin:唯一写入点astrbot/core/star/star_manager.pyturn_on_plugin:唯一清理点(但不在重启路径中)astrbot/dashboard/routes/plugin.pyturn_on_plugin的唯一入口Expected behavior / 期望行为
load()在所有插件加载完成后,遍历所有activated=True的插件已注册的工具,将匹配条目从inactivated_llm_tools中清除并恢复active:注意:此修复仅针对"因插件整体停用而写入黑名单的工具"。由于
inactivated_llm_tools是扁平列表,不区分"因插件停用而关闭"和"用户单独手动关闭",用户单独关闭的工具也会在重启后被恢复。这是inactivated_llm_tools架构层面的缺陷(turn_on_plugin目前同样有此问题),彻底的修复需要将两套语义分开存储(例如新增inactivated_plugins作为独立判断依据),不在本 issue 范围内。Reproduce / 如何复现?
turn_off_plugin将 N 个工具名写入 DBturn_on_plugin,清理成功)turn_on_plugin)→load()从 DB 读取黑名单 → 工具被设为active=Falseload()再次读取 → 工具再次被关闭黑名单条目不会被任何重启路径清理,只能通过 WebUI 启用插件来清除。
AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
OS
Windows
Logs / 报错日志
无显式报错。
Are you willing to submit a PR? / 你愿意提交 PR 吗?
Code of Conduct