Skip to content

feat:Support hot reload after plugin load failure#5043

Merged
Soulter merged 4 commits intoAstrBotDevs:masterfrom
Waterwzy:issue/5041
Feb 13, 2026
Merged

feat:Support hot reload after plugin load failure#5043
Soulter merged 4 commits intoAstrBotDevs:masterfrom
Waterwzy:issue/5041

Conversation

@Waterwzy
Copy link
Contributor

@Waterwzy Waterwzy commented Feb 11, 2026

Modifications / 改动点

Relate to #5041

一:astrbot/core/star/star_manager.py

  • 初始化时增加字典 self.failed_plugin_dict = {} ,方便后续热重载

  • 增加方法 reload_failed_plugin( self , dir_name ) ,通过调用 load(self, specified_module_path=None, specified_dir_name=None) 重载加载失败的插件 。

  • 在方法 load(self, specified_module_path=None, specified_dir_name=None) 加载插件失败时,将相关信息写入 self.failed_plugin_dict ,记录相关插件信息。

二: astrbot/dashboard/routes/plugin.py

  • 增加请求路径 /plugin/reload-failed(POST),用于重载加载失败的插件,并且绑定 reload_failed_plugins(self) 方法。

  • 增加请求路径 /plugin/source/get-failed-plugins(GET),用于获取重载失败插件字典,并且绑定 get_failed_plugins(self) 方法。

三: dashboard/src/views/ExtensionPage.vue

  • 增加 handleReloadAllFailed 函数,用于处理重载加载失败插件。

  • 调整 getExtensions 函数,使其可以获得加载失败插件字典。

  • 更改前端组件,使其显示重载按钮。

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果


4D2CDEE3B1E61938CD1DDEB7E8686587

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

添加支持识别和热重载加载失败的插件,并通过 API 和仪表板 UI 对外提供这一能力。

新功能:

  • 跟踪加载失败插件的元数据,以便之后尝试热重载。
  • 提供后端 API 端点,用于查询失败的插件并触发对单个失败插件的重载。
  • 在仪表板中提供控件,一键尝试重载所有先前加载失败的插件。

改进:

  • 扩展插件加载流程,持久化失败插件加载的详细错误信息,以供后续排查。
Original summary in English

Summary by Sourcery

Add support for identifying and hot reloading plugins that failed to load, exposing this capability via API and the dashboard UI.

New Features:

  • Track metadata about plugins that fail to load to enable later hot reload attempts.
  • Provide backend API endpoints to query failed plugins and trigger reload of individual failed plugins.
  • Expose a dashboard control to attempt one-click reload of all previously failed plugins.

Enhancements:

  • Extend plugin loading process to persist detailed error information for failed plugin loads for later inspection.
Original summary in English

Summary by Sourcery

添加支持识别和热重载加载失败的插件,并通过 API 和仪表板 UI 对外提供这一能力。

新功能:

  • 跟踪加载失败插件的元数据,以便之后尝试热重载。
  • 提供后端 API 端点,用于查询失败的插件并触发对单个失败插件的重载。
  • 在仪表板中提供控件,一键尝试重载所有先前加载失败的插件。

改进:

  • 扩展插件加载流程,持久化失败插件加载的详细错误信息,以供后续排查。
Original summary in English

Summary by Sourcery

Add support for identifying and hot reloading plugins that failed to load, exposing this capability via API and the dashboard UI.

New Features:

  • Track metadata about plugins that fail to load to enable later hot reload attempts.
  • Provide backend API endpoints to query failed plugins and trigger reload of individual failed plugins.
  • Expose a dashboard control to attempt one-click reload of all previously failed plugins.

Enhancements:

  • Extend plugin loading process to persist detailed error information for failed plugin loads for later inspection.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 11, 2026
@dosubot
Copy link

dosubot bot commented Feb 11, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些整体反馈:

  • handleReloadAllFailed 中,loading_.value 在检查 dirNames.length 之前就被设置为 true,但如果没有失败的插件,会在没有重置它的情况下提前 return,这样就有可能导致 loading 状态被卡住;可以把 loading_.value = true 移到提前返回检查之后,或者在返回之前确保它被重置。
  • 模板中调用的是 @click="handleReloadAllFailed(isActive)",但 handleReloadAllFailed 的定义没有参数,也没有使用 isActive,所以要么在模板中移除这个参数,要么修改函数签名以接收并使用它。
给 AI Agent 的提示
请根据以下代码评审意见进行修改:

## 整体评论
-`handleReloadAllFailed` 中,`loading_.value` 在检查 `dirNames.length` 之前就被设置为 `true`,但如果没有失败的插件,会在没有重置它的情况下提前 `return`,这样就有可能导致 loading 状态被卡住;可以把 `loading_.value = true` 移到提前返回检查之后,或者在返回之前确保它被重置。
- 模板中调用的是 `@click="handleReloadAllFailed(isActive)"`,但 `handleReloadAllFailed` 的定义没有参数,也没有使用 `isActive`,所以要么在模板中移除这个参数,要么修改函数签名以接收并使用它。

## 单独评论

### 评论 1
<location> `dashboard/src/views/ExtensionPage.vue:1300-1302` </location>
<code_context>
+                              color="error"
+                              variant="tonal"
+                              prepend-icon="mdi-refresh"
+                              @click="handleReloadAllFailed(isActive)"
+                          >
+                              尝试一键重载修复
</code_context>

<issue_to_address>
**suggestion:** 点击事件处理函数接收了 `isActive`,但 `handleReloadAllFailed` 没有接收或使用任何参数。

由于 `handleReloadAllFailed` 不接收任何参数,这里传入 `isActive` 实际上不会产生任何效果,还可能造成误导。根据预期行为,要么在模板中移除这个参数,要么更新函数签名以使用它。

```suggestion
                              prepend-icon="mdi-refresh"
                              @click="handleReloadAllFailed"
                          >
```
</issue_to_address>

Sourcery 对开源项目免费 —— 如果你觉得这次评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In handleReloadAllFailed, loading_.value is set to true before checking dirNames.length, but if there are no failed plugins you return early without resetting it, so the loading state can get stuck; move the loading_.value = true after the early-return check or ensure it is reset before returning.
  • The template calls @click="handleReloadAllFailed(isActive)" but handleReloadAllFailed is defined without parameters and does not use isActive, so either remove the argument from the template or update the function signature to accept and use it.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `handleReloadAllFailed`, `loading_.value` is set to `true` before checking `dirNames.length`, but if there are no failed plugins you `return` early without resetting it, so the loading state can get stuck; move the `loading_.value = true` after the early-return check or ensure it is reset before returning.
- The template calls `@click="handleReloadAllFailed(isActive)"` but `handleReloadAllFailed` is defined without parameters and does not use `isActive`, so either remove the argument from the template or update the function signature to accept and use it.

## Individual Comments

### Comment 1
<location> `dashboard/src/views/ExtensionPage.vue:1300-1302` </location>
<code_context>
+                              color="error"
+                              variant="tonal"
+                              prepend-icon="mdi-refresh"
+                              @click="handleReloadAllFailed(isActive)"
+                          >
+                              尝试一键重载修复
</code_context>

<issue_to_address>
**suggestion:** The click handler is passed `isActive` but `handleReloadAllFailed` does not accept or use any parameters.

Since `handleReloadAllFailed` doesn’t take any parameters, passing `isActive` here has no effect and can be misleading. Either remove the argument in the template or update the function signature to use it, depending on the intended behavior.

```suggestion
                              prepend-icon="mdi-refresh"
                              @click="handleReloadAllFailed"
                          >
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot dosubot bot added area:webui The bug / feature is about webui(dashboard) of astrbot. feature:plugin The bug / feature is about AstrBot plugin system. labels Feb 11, 2026
@Waterwzy Waterwzy changed the title add :Support hot reload after plugin load failure feat:Support hot reload after plugin load failure Feb 11, 2026
Waterwzy and others added 3 commits February 11, 2026 22:02
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@Waterwzy
Copy link
Contributor Author

@sourcery-ai review

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里留下了一些整体反馈:

  • StarManager.load 中,failed_plugin_dict 只会在加载失败时追加条目,但在每次加载开始时都不会被清空,这会导致在之后加载成功时仍然保留过期的失败记录;建议在重新尝试加载之前/之时清空它(或按插件移除对应条目),以便状态能够准确反映当前的失败情况。
  • 新增的 /plugin/source/get-failed-plugins 接口直接返回了 plugin_manager.failed_plugin_dict;返回一个浅拷贝会更好,可以避免外部调用方无意中修改管理器的内部状态。
  • 在前端中,getExtensions 目前会按顺序发起两个 HTTP 请求(先 /plugin/get/plugin/source/get-failed-plugins);可以使用 Promise.all 并行请求两者,从而降低扩展页面的感知延迟。
给 AI 智能体的提示
Please address the comments from this code review:

## Overall Comments
- In `StarManager.load`, `failed_plugin_dict` is only appended to on failures and never cleared at the beginning of a load pass, which can leave stale failure entries after a later successful load; consider clearing it (or removing entries per plugin) before/when re-attempting loads so the state accurately reflects current failures.
- The new `/plugin/source/get-failed-plugins` endpoint returns `plugin_manager.failed_plugin_dict` directly; returning a shallow copy instead would prevent accidental external mutation of internal manager state.
- On the frontend, `getExtensions` performs two sequential HTTP requests (`/plugin/get` then `/plugin/source/get-failed-plugins`); these can be requested in parallel with `Promise.all` to reduce perceived latency of the extensions page.

Sourcery 对开源项目是免费的——如果你觉得这些 Review 有帮助,欢迎分享它们 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English

Hey - I've left some high level feedback:

  • In StarManager.load, failed_plugin_dict is only appended to on failures and never cleared at the beginning of a load pass, which can leave stale failure entries after a later successful load; consider clearing it (or removing entries per plugin) before/when re-attempting loads so the state accurately reflects current failures.
  • The new /plugin/source/get-failed-plugins endpoint returns plugin_manager.failed_plugin_dict directly; returning a shallow copy instead would prevent accidental external mutation of internal manager state.
  • On the frontend, getExtensions performs two sequential HTTP requests (/plugin/get then /plugin/source/get-failed-plugins); these can be requested in parallel with Promise.all to reduce perceived latency of the extensions page.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `StarManager.load`, `failed_plugin_dict` is only appended to on failures and never cleared at the beginning of a load pass, which can leave stale failure entries after a later successful load; consider clearing it (or removing entries per plugin) before/when re-attempting loads so the state accurately reflects current failures.
- The new `/plugin/source/get-failed-plugins` endpoint returns `plugin_manager.failed_plugin_dict` directly; returning a shallow copy instead would prevent accidental external mutation of internal manager state.
- On the frontend, `getExtensions` performs two sequential HTTP requests (`/plugin/get` then `/plugin/source/get-failed-plugins`); these can be requested in parallel with `Promise.all` to reduce perceived latency of the extensions page.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 12, 2026
Copy link
Member

@Soulter Soulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没太大问题,ruff format 一下

@Soulter
Copy link
Member

Soulter commented Feb 12, 2026

或者是否可以做到载入失败的插件也显示在插件页,但是有相应载入失败的提示,也可以重新载入。这样是否自由度会高一些

@Waterwzy
Copy link
Contributor Author

或者是否可以做到载入失败的插件也显示在插件页,但是有相应载入失败的提示,也可以重新载入。这样是否自由度会高一些

这个逻辑没改,载入失败的插件会在插件页显示红色感叹号,点进去就是详细信息和重载提示

@Waterwzy Waterwzy force-pushed the issue/5041 branch 2 times, most recently from 0f7c480 to ca15230 Compare February 12, 2026 13:17
@Waterwzy
Copy link
Contributor Author

没太大问题,ruff format 一下

很奇怪,报错的ruff文件我在这个pr里完全没动过,而且本地的ruff跑出来也没问题。

@Waterwzy Waterwzy requested a review from Soulter February 12, 2026 14:21
@Soulter Soulter merged commit 0faf109 into AstrBotDevs:master Feb 13, 2026
9 of 10 checks passed
astrbot-doc-agent bot pushed a commit to AstrBotDevs/AstrBot-docs that referenced this pull request Feb 13, 2026
@astrbot-doc-agent
Copy link

Generated docs update PR (pending manual review):
AstrBotDevs/AstrBot-docs#126
Trigger: PR merged


AI change summary:

  • 更新了 zh/use/webui.md 与 en/use/webui.md,新增“插件加载失败处理”章节,介绍 WebUI 错误提示及一键重载功能。
  • 更新了 zh/dev/star/plugin-new.md 与 en/dev/star/plugin-new.md,在调试插件章节补充了重载失败插件的操作说明,提升开发调试效率。
  • 本次更新已同步完成中英文(zh/en)文档的对应修改。

Experimental bot notice:

  • This output is generated by AstrBot-Doc-Agent for review only.
  • It does not represent the final documentation form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. feature:plugin The bug / feature is about AstrBot plugin system. lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants