Fix(#6749): allow batch resetting provider config to "follow#6825
Fix(#6749): allow batch resetting provider config to "follow#6825M1LKT wants to merge 4 commits intoAstrBotDevs:masterfrom
Conversation
…mprove batch operation logic
…void collisions with provider IDs
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The magic string 'astrbot_follow_config' is repeated in multiple places on the frontend; consider extracting it into a shared constant to avoid typos and make future changes easier.
- You added
batchTtsProviderOptionsbut the batch TTS select still appears to use the originalttsProviderOptions; please confirm the correct options source is wired up or remove the unused computed to avoid confusion. - Enabling
config.use_reloader = Trueinserver.pyaffects runtime behavior and may not be desirable in non‑development environments; consider making this conditional on an environment flag or local dev setting.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The magic string '__astrbot_follow_config__' is repeated in multiple places on the frontend; consider extracting it into a shared constant to avoid typos and make future changes easier.
- You added `batchTtsProviderOptions` but the batch TTS select still appears to use the original `ttsProviderOptions`; please confirm the correct options source is wired up or remove the unused computed to avoid confusion.
- Enabling `config.use_reloader = True` in `server.py` affects runtime behavior and may not be desirable in non‑development environments; consider making this conditional on an environment flag or local dev setting.
## Individual Comments
### Comment 1
<location path="dashboard/src/views/SessionManagementPage.vue" line_range="674" />
<code_context>
chatProviderOptions() {
return [
- { label: this.tm('provider.followConfig'), value: null },
+ { label: this.tm('provider.followConfig'), value: '__astrbot_follow_config__' },
...this.availableChatProviders.map(p => ({
label: `${p.name} (${p.model})`,
</code_context>
<issue_to_address>
**suggestion:** Extract the follow-config sentinel string into a shared constant to avoid duplication and typo risk.
The `'__astrbot_follow_config__'` literal appears in several places (defaults, options, checks). Please define a single shared constant (e.g. `const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'` or a `data`/`computed` property) and reference it everywhere to avoid typos and simplify future changes.
Suggested implementation:
```
const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'
chat_completion: FOLLOW_CONFIG_SENTINEL,
speech_to_text: FOLLOW_CONFIG_SENTINEL,
text_to_speech: FOLLOW_CONFIG_SENTINEL,
},
// 插件配置
chatProviderOptions() {
return [
{ label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
...this.availableChatProviders.map(p => ({
label: `${p.name} (${p.model})`,
value: p.id
sttProviderOptions() {
return [
{ label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
...this.availableSttProviders.map(p => ({
label: `${p.name} (${p.model})`,
value: p.id
```
1. Place the `const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'` declaration at the top of the `<script>` block (or just after existing imports) to match your project's conventions; the SEARCH/REPLACE block above assumes this snippet is near the top of the script, but you may need to move the constant accordingly.
2. Search the remainder of `SessionManagementPage.vue` for any other occurrences of `'__astrbot_follow_config__'` (e.g. in watchers, computed properties, validation logic) and replace them with `FOLLOW_CONFIG_SENTINEL` as well.
3. If this sentinel is used in other files (e.g. shared stores or components), consider moving `FOLLOW_CONFIG_SENTINEL` into a shared constants module (e.g. `src/constants/providers.ts`) and importing it here and elsewhere to fully centralize the value.
</issue_to_address>
### Comment 2
<location path="astrbot/dashboard/routes/session_management.py" line_range="384-385" />
<code_context>
if not isinstance(umos, list):
return Response().error("参数 umos 必须是数组").__dict__
+ if rule_key and rule_key not in AVAILABLE_SESSION_RULE_KEYS:
+ return Response().error(f"不支持的规则键: {rule_key}").__dict__
+
# 批量删除
</code_context>
<issue_to_address>
**suggestion:** Consider validating `scope` values explicitly to produce clearer errors for invalid input.
An unsupported `scope` (e.g. a typo) currently just leaves `umos` empty and triggers the generic "缺少必要参数: umos 或有效的 scope" error, which hides that `scope` itself was invalid. Please validate `scope` against the allowed set and return a specific error (e.g. "不支持的 scope 值") before expanding it into `umos` so invalid scopes aren’t treated the same as missing `umos`.
Suggested implementation:
```python
elif scope == "all":
umos = all_umos
# 显式校验 scope,避免无效 scope 静默失败
allowed_scopes = {"all"}
if scope and scope not in allowed_scopes:
return Response().error("不支持的 scope 值").__dict__
if not umos:
return Response().error("缺少必要参数: umos 或有效的 scope").__dict__
```
To fully align this change with the rest of the function:
1. Update `allowed_scopes` to include all currently支持的 scope 值(例如如果上文有 `if scope == "online"`, `if scope == "selected"` 等分支,请将这些字符串也加入到 `allowed_scopes` 集合中),确保不会误报合法 scope 为无效。
2. If there is a centralized definition of allowed scopes elsewhere in the codebase (e.g. a constant like `AVAILABLE_SESSION_SCOPES`), replace the hardcoded `allowed_scopes` set with that constant to keep things DRY and consistent.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| chatProviderOptions() { | ||
| return [ | ||
| { label: this.tm('provider.followConfig'), value: null }, | ||
| { label: this.tm('provider.followConfig'), value: '__astrbot_follow_config__' }, |
There was a problem hiding this comment.
suggestion: Extract the follow-config sentinel string into a shared constant to avoid duplication and typo risk.
The '__astrbot_follow_config__' literal appears in several places (defaults, options, checks). Please define a single shared constant (e.g. const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__' or a data/computed property) and reference it everywhere to avoid typos and simplify future changes.
Suggested implementation:
const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'
chat_completion: FOLLOW_CONFIG_SENTINEL,
speech_to_text: FOLLOW_CONFIG_SENTINEL,
text_to_speech: FOLLOW_CONFIG_SENTINEL,
},
// 插件配置
chatProviderOptions() {
return [
{ label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
...this.availableChatProviders.map(p => ({
label: `${p.name} (${p.model})`,
value: p.id
sttProviderOptions() {
return [
{ label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
...this.availableSttProviders.map(p => ({
label: `${p.name} (${p.model})`,
value: p.id
- Place the
const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'declaration at the top of the<script>block (or just after existing imports) to match your project's conventions; the SEARCH/REPLACE block above assumes this snippet is near the top of the script, but you may need to move the constant accordingly. - Search the remainder of
SessionManagementPage.vuefor any other occurrences of'__astrbot_follow_config__'(e.g. in watchers, computed properties, validation logic) and replace them withFOLLOW_CONFIG_SENTINELas well. - If this sentinel is used in other files (e.g. shared stores or components), consider moving
FOLLOW_CONFIG_SENTINELinto a shared constants module (e.g.src/constants/providers.ts) and importing it here and elsewhere to fully centralize the value.
| if rule_key and rule_key not in AVAILABLE_SESSION_RULE_KEYS: | ||
| return Response().error(f"不支持的规则键: {rule_key}").__dict__ |
There was a problem hiding this comment.
suggestion: Consider validating scope values explicitly to produce clearer errors for invalid input.
An unsupported scope (e.g. a typo) currently just leaves umos empty and triggers the generic "缺少必要参数: umos 或有效的 scope" error, which hides that scope itself was invalid. Please validate scope against the allowed set and return a specific error (e.g. "不支持的 scope 值") before expanding it into umos so invalid scopes aren’t treated the same as missing umos.
Suggested implementation:
elif scope == "all":
umos = all_umos
# 显式校验 scope,避免无效 scope 静默失败
allowed_scopes = {"all"}
if scope and scope not in allowed_scopes:
return Response().error("不支持的 scope 值").__dict__
if not umos:
return Response().error("缺少必要参数: umos 或有效的 scope").__dict__To fully align this change with the rest of the function:
- Update
allowed_scopesto include all currently支持的 scope 值(例如如果上文有if scope == "online",if scope == "selected"等分支,请将这些字符串也加入到allowed_scopes集合中),确保不会误报合法 scope 为无效。 - If there is a centralized definition of allowed scopes elsewhere in the codebase (e.g. a constant like
AVAILABLE_SESSION_SCOPES), replace the hardcodedallowed_scopesset with that constant to keep things DRY and consistent.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses issue #6749, which prevented users from resetting multiple sessions to the global Provider configuration in the "Custom Rules → Batch Operations" scenario. The frontend now uses an explicit state to represent "Follow Configuration," and the backend has been enhanced with the ability to batch delete rules, enabling a true reversion to the global Provider. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
本次拉取请求修复了批量重置提供商配置为“跟随配置文件”的问题,通过在前端使用显式字符串 __astrbot_follow_config__ 代替 null 来表示“跟随配置文件”状态,并相应地调整了批量操作的逻辑。后端扩展了 batch_delete_session_rule 接口,使其能够根据 scope 和 rule_key 批量删除会话规则,从而实现回退到全局配置。这些改动提高了配置管理的清晰度和灵活性。但在后端代码中发现一个关键的 NameError,以及一些可以改进的地方。
I am having trouble creating individual review comments. Click here to see my feedback.
astrbot/dashboard/routes/session_management.py (385)
变量 AVAILABLE_SESSION_RULE_KEYS 在此文件中未定义。这会导致 NameError,从而使 API 端点无法正常工作。请确保在使用前导入或定义此变量。
astrbot/dashboard/routes/session_management.py (364-374)
当前通过 user_id 字符串中是否包含 ':group:' 或 ':private:' 来判断会话类型,这种方式依赖于 user_id 的特定格式。如果 user_id 的生成规则发生变化,这部分逻辑可能会失效。建议考虑是否有更健壮的方式来识别会话类型,例如在 ConversationV2 或 PlatformSession 模型中增加一个明确的 is_group 或 chat_type 字段。
astrbot/dashboard/server.py (374)
将 config.use_reloader 设置为 True 对于开发环境非常有用,因为它可以在代码更改时自动重新加载服务器。然而,在生产环境中,这通常会导致性能开销和潜在的稳定性问题。建议根据环境(例如通过环境变量)来动态设置此值,在生产环境中将其设置为 False。
dashboard/src/views/SessionManagementPage.vue (691-717)
你为 chatProviderOptions 和 ttsProviderOptions 创建了 batchChatProviderOptions 和 batchTtsProviderOptions。然而,sttProviderOptions 并没有对应的 batchSttProviderOptions。如果 STT 提供商也需要进行批量操作,那么也应该为其创建一个 batchSttProviderOptions 以保持一致性,并确保所有批量操作功能完整。
Motivation / 改动动机
修复 Issue #6749:
在“自定义规则 → 批量操作”场景中,无法通过“跟随配置文件”一次性将多个会话恢复为全局 Provider(聊天模型)。
原因是前端早期用
null同时表示“未修改”和“跟随配置”,导致界面无法区分“保持不变”和“批量还原为全局”的意图,从而无法实现一键恢复默认配置。本 PR 的目标是:
scope/group_id/rule_key),用于真正删除会话级覆盖配置,从而回退到全局 Provider。Summary / 改动摘要(前端 + 后端)
dashboard/src/views/SessionManagementPage.vuenull表示,改为显式字符串(示例值:'follow'或项目内部常量__astrbot_follow_config__)。POST /api/session/batch-delete-rule),并携带rule_key(例如provider_perf_chat_completion)以删除对应覆盖;当选择具体 provider 时,仍走POST /api/session/batch-update-provider。'follow';保存时若选择'follow'则触发删除逻辑(调用后端删除单条 rule),否则写入覆盖配置。canApplyBatch保持原意——只有在至少选择一项修改且范围满足时才启用,“跟随”作为显式修改项被计入。astrbot/dashboard/routes/session_management.pybatch_delete_session_rule仿照batch_update_provider,支持接收umos列表或scope(all|group|private|custom_group)和group_id,并支持rule_key参数用于只删除特定规则(例如provider_perf_chat_completion)。delete_session_rule(单条删除)逻辑对齐:当传入rule_key时仅删除该 key,否则删除该umo下全部规则。batch_update_provider的语义(用于写入/覆盖 provider),但批量恢复(跟随)不再通过写入特殊值实现,而是参考修改单个会话时的操作,通过删除覆盖规则实现回退。Screenshots or Test Results / 运行截图或测试结果
PixPin_2026-03-23_10-34-29.mp4
验证步骤(Testing / QA)
Preference表中provider_perf_chat_completion对应记录被删除;在界面上该条目显示为“跟随配置文件”。group(或selected并选择多项),将聊天模型选择为“跟随配置文件”,应用。provider_perf_chat_completion覆盖记录被删除;会话实际使用全局 provider(可以通过触发一次对话并观察 provider 选择或日志来确认)。batch_update_provider在选择具体 provider_id 时仍旧能正确写入覆盖。受影响文件列表
Dashboard (前端)
dashboard/src/views/SessionManagementPage.vue— Provider 选项、批量提交逻辑、规则编辑器初始化保存逻辑Backend (API)
astrbot/dashboard/routes/session_management.py— 扩展batch_delete_session_rule,并保证delete_session_rule与之行为一致(变更均为本次 PR 的核心改动;其他关联小改动以代码 diff 为准)
Checklist / 检查清单
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。/ 我的更改没有引入恶意代码。