Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 133 additions & 2 deletions astrbot/core/astrbot_config_mgr.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import os
import uuid
from contextvars import Token
from typing import TypedDict, TypeVar

from astrbot.core import AstrBotConfig, logger
from astrbot.core.config.astrbot_config import ASTRBOT_CONFIG_PATH
from astrbot.core.config.default import DEFAULT_CONFIG
from astrbot.core.config.overrides import (
CORE_CONFIG_OVERRIDE_KEY,
build_effective_core_config,
build_effective_core_config_sync,
get_current_effective_config,
normalize_config_override_payload,
remove_core_config_override_paths,
reset_current_effective_config,
set_current_effective_config,
update_core_config_override_paths,
)
from astrbot.core.platform.message_session import MessageSession
from astrbot.core.umop_config_router import UmopConfigRouter
from astrbot.core.utils.astrbot_path import get_astrbot_config_path
Expand All @@ -31,6 +43,8 @@ class ConfInfo(TypedDict):
class AstrBotConfigManager:
"""A class to manage the system configuration of AstrBot, aka ACM"""

core_config_override_key = CORE_CONFIG_OVERRIDE_KEY

def __init__(
self,
default_config: AstrBotConfig,
Expand Down Expand Up @@ -121,8 +135,15 @@ def _save_conf_mapping(
self.sp.put("abconf_mapping", abconf_data, scope="global", scope_id="global")
self.abconf_data = abconf_data

def get_conf(self, umo: str | MessageSession | None) -> AstrBotConfig:
"""获取指定 umo 的配置文件。如果不存在,则 fallback 到默认配置文件。"""
def get_base_conf(self, umo: str | MessageSession | None) -> AstrBotConfig:
"""Get the base config profile for a UMO without applying overrides.

Args:
umo: Unified message origin or message session.

Returns:
Shared base config profile selected for the UMO.
"""
if not umo:
return self.confs["default"]
if isinstance(umo, MessageSession):
Expand All @@ -136,6 +157,116 @@ def get_conf(self, umo: str | MessageSession | None) -> AstrBotConfig:

return conf

def get_conf(self, umo: str | MessageSession | None = None) -> AstrBotConfig:
"""获取指定 umo 的配置文件。如果不存在,则 fallback 到默认配置文件。"""
umo_str = None
if umo:
umo_str = (
f"{umo.platform_id}:{umo.message_type}:{umo.session_id}"
if isinstance(umo, MessageSession)
else str(umo)
)

effective_config = get_current_effective_config(umo_str)
if effective_config:
return effective_config

if not umo:
effective_config = get_current_effective_config()
if effective_config:
return effective_config
return self.confs["default"]
Comment on lines +174 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The second call to get_current_effective_config() is redundant because if umo is None, get_current_effective_config(None) was already called on line 170 and would have returned the effective config if it existed. We can simplify this block to directly return the default configuration.

Suggested change
if not umo:
effective_config = get_current_effective_config()
if effective_config:
return effective_config
return self.confs["default"]
if not umo:
return self.confs["default"]


base_config = self.get_base_conf(umo)
return build_effective_core_config_sync(
base_config, self.sp, umo_str or str(umo)
)

def get_current_conf(self, default: AstrBotConfig | None = None) -> AstrBotConfig:
"""Get the active task config or a caller-provided default config.

Args:
default: Config returned when no event-scoped config is active.

Returns:
Active effective config, default config, or the global default profile.
"""
return get_current_effective_config() or default or self.confs["default"]

async def build_effective_conf(
self,
umo: str,
base_config: AstrBotConfig | None = None,
) -> AstrBotConfig:
"""Build an effective config for one UMO.

Args:
umo: Unified message origin.
base_config: Optional already-selected base config profile.

Returns:
Config view with UMO overrides applied.
"""
return await build_effective_core_config(
base_config or self.get_base_conf(umo),
self.sp,
umo,
)

def activate_effective_conf(
self,
umo: str,
config: AstrBotConfig,
) -> Token:
"""Bind an effective config to the current async task.

Args:
umo: Unified message origin.
config: Effective config for the current event.

Returns:
Context variable token used to reset the binding.
"""
return set_current_effective_config(umo, config)

def reset_effective_conf(self, token: Token) -> None:
"""Reset the current task's effective config binding.

Args:
token: Token returned by activate_effective_conf.
"""
reset_current_effective_config(token)

async def update_conf_overrides(self, umo: str, paths: dict) -> None:
"""Merge config override paths for one UMO.

Args:
umo: Unified message origin.
paths: Dot-separated config path to override value mapping.
"""
await update_core_config_override_paths(self.sp, umo, paths)

@staticmethod
def normalize_conf_override_payload(payload: object) -> dict:
"""Normalize a config override payload into path-value pairs.

Args:
payload: Raw preference value for a config override.

Returns:
Dot-separated config path to override value mapping.
"""
return normalize_config_override_payload(payload)

async def remove_conf_overrides(self, umo: str, paths: list[str]) -> None:
"""Remove config override paths for one UMO.

Args:
umo: Unified message origin.
paths: Dot-separated config paths to remove.
"""
await remove_core_config_override_paths(self.sp, umo, paths)

@property
def default_conf(self) -> AstrBotConfig:
"""获取默认配置文件"""
Expand Down
19 changes: 19 additions & 0 deletions astrbot/core/config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"forward_threshold": 1500,
"enable_id_white_list": True,
"id_whitelist": [],
"id_blacklist": [],
"id_whitelist_log": True,
"wl_ignore_admin_on_group": True,
"wl_ignore_admin_on_friend": True,
Expand Down Expand Up @@ -306,6 +307,7 @@
"callback_api_base": "",
"default_kb_collection": "", # 默认知识库名称, 已经过时
"plugin_set": ["*"], # "*" 表示使用所有可用的插件, 空列表表示不使用任何插件
"plugin_disabled_set": [],
"kb_names": [], # 默认知识库名称列表
"kb_fusion_top_k": 20, # 知识库检索融合阶段返回结果数量
"kb_final_top_k": 5, # 知识库检索最终返回结果数量
Expand Down Expand Up @@ -1087,6 +1089,11 @@
"items": {"type": "string"},
"hint": "只处理填写的 ID 发来的消息事件,为空时不启用。可使用 /sid 指令获取在平台上的会话 ID(类似 abc:GroupMessage:123)。管理员可在 WebUI 的平台设置中管理白名单",
},
"id_blacklist": {
"type": "list",
"items": {"type": "string"},
"hint": "拒绝处理填写的 ID 发来的消息事件。命中黑名单时会优先于白名单被拒绝。",
},
"id_whitelist_log": {
"type": "bool",
"hint": "启用后,当一条消息没通过白名单时,会输出 INFO 级别的日志。",
Expand Down Expand Up @@ -3924,6 +3931,12 @@
"items": {"type": "string"},
"hint": "使用 /sid 获取 ID。当白名单列表为空时,代表不启用白名单(即所有 ID 都在白名单内)。",
},
"platform_settings.id_blacklist": {
"description": "黑名单 ID 列表",
"type": "list",
"items": {"type": "string"},
"hint": "使用 /sid 获取 ID。命中黑名单的会话会被拒绝,黑名单优先于白名单。",
},
"platform_settings.id_whitelist_log": {
"description": "输出日志",
"type": "bool",
Expand Down Expand Up @@ -4090,6 +4103,12 @@
"hint": "默认启用全部未被禁用的插件。若插件在插件页面被禁用,则此处的选择不会生效。",
"_special": "select_plugin_set",
},
"plugin_disabled_set": {
"description": "禁用插件",
"type": "bool",
"hint": "明确禁用的插件列表。命中禁用列表的插件不会在会话中触发。",
"_special": "select_plugin_set",
},
},
},
},
Expand Down
Loading
Loading