这一批提交包含: 1. 配置项敏感字段标记与测试用例修复 2. 路由绑定乐观锁支持与静态路径校验 3. 微信WOC插件能力适配与新增单元测试 4. 多个适配器的接口对齐与测试补全 5. 新增定时任务清理处理器与依赖注入容器测试 6. 错误码体系扩展与整合测试 7. 删除临时验证脚本与代码清理
622 lines
22 KiB
Python
622 lines
22 KiB
Python
"""配置 schema 元数据契约层定义。
|
||
|
||
定义配置字段的完整 schema 元数据(``CONFIG_SCHEMA``),包括键、类型、
|
||
是否必填、默认值、是否可热更新与约束,作为配置 schema 的唯一真相源
|
||
(§13.1 配置分层 / §6.1 契约层职责)。适配器(如 ``RedisConfigAdapter``)
|
||
与应用层(如 ``ConfigManager``)共享引用本模块,消除 schema 元数据
|
||
下沉至适配器层的 DRY 违反。
|
||
|
||
``HOT_RELOADABLE_KEYS`` / ``NON_HOT_RELOADABLE_KEYS`` 从 ``CONFIG_SCHEMA``
|
||
派生,供 ``ConfigManager`` 做热更新策略校验(ADP-030)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from yuxi.channels.contract.dtos.config import ConfigField
|
||
|
||
# 配置 schema:全部配置字段的完整元数据(FR-37 配置热更新)。
|
||
# 40 个可热更新字段 + 13 个不可热更新字段,共 53 个。
|
||
# 字段顺序:先可热更新(hot_reloadable=True),后不可热更新(hot_reloadable=False)。
|
||
CONFIG_SCHEMA: tuple[ConfigField, ...] = (
|
||
# === 可热更新字段(hot_reloadable=True)===
|
||
ConfigField(
|
||
key="dm_policy",
|
||
type="json",
|
||
required=False,
|
||
default="allow",
|
||
hot_reloadable=True,
|
||
title="私信策略",
|
||
description="控制私信/群聊的自动回复与路由策略,如是否允许陌生人私信、是否自动创建会话等。",
|
||
category="消息策略",
|
||
),
|
||
ConfigField(
|
||
key="allow_from",
|
||
type="json",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=True,
|
||
title="来源白名单",
|
||
description="允许向当前账户发起对话的对端白名单,未配置时不限制。",
|
||
category="访问控制",
|
||
),
|
||
ConfigField(
|
||
key="rate_limit",
|
||
type="json",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=True,
|
||
title="消息限流",
|
||
description="控制账户级别的消息发送频率限制,防止滥用或触发渠道风控。",
|
||
category="限流与预算",
|
||
),
|
||
ConfigField(
|
||
key="bot_loop_budget",
|
||
type="json",
|
||
required=False,
|
||
default={"max_replies_per_hour": 20, "cooldown_seconds": 60},
|
||
hot_reloadable=True,
|
||
title="Bot 循环预算",
|
||
description=(
|
||
"Bot 循环预算配置,包含 max_replies_per_hour"
|
||
"(每小时最大回复数,≤0 表示不限制)和 cooldown_seconds(冷却秒数)。"
|
||
),
|
||
category="限流与预算",
|
||
),
|
||
# FR-08~14 功能开关(Task 30)
|
||
ConfigField(
|
||
key="rich_message_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="富消息开关",
|
||
description="是否启用富媒体消息(卡片、按钮等)发送能力。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="status_writeback_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="状态回写开关",
|
||
description="是否将渠道用户状态(在线/离开等)回写到知识库。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="agent_prompt_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="Agent 提示开关",
|
||
description="是否在消息中附加 Agent 提示上下文。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="channel_tools_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="渠道工具开关",
|
||
description="是否允许 Agent 调用渠道相关工具。",
|
||
category="功能开关",
|
||
),
|
||
# AC-22: 消息操作开关默认"开"(FR-12)
|
||
ConfigField(
|
||
key="message_ops_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="消息操作开关",
|
||
description="总开关:是否启用消息操作(反应、置顶、卡片更新等)。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="streaming_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="流式响应开关",
|
||
description="是否启用流式(打字机效果)响应输出。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="enable_typing",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="输入中提示开关",
|
||
description="是否向用户展示'正在输入'状态提示。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="directory_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="目录服务开关",
|
||
description="是否启用渠道目录(用户/群组列表)查询能力。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="command_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="命令处理开关",
|
||
description="是否启用以 command_prefix 开头的命令解析与处理。",
|
||
category="功能开关",
|
||
),
|
||
# FR-12 消息操作细粒度开关(PRD §FR-12 配置项)。
|
||
# AC-22 默认行为:表情反应"开"、置顶"关"、卡片更新"关"。
|
||
ConfigField(
|
||
key="enable_reaction",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="表情反应开关",
|
||
description="是否允许对消息添加表情反应。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="enable_pin",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="消息置顶开关",
|
||
description="是否允许置顶/取消置顶消息。",
|
||
category="功能开关",
|
||
),
|
||
ConfigField(
|
||
key="enable_card_update",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="卡片更新开关",
|
||
description="是否允许更新已发送的卡片消息。",
|
||
category="功能开关",
|
||
),
|
||
# FR-15 管理员命令权限白名单(账户级,JSON 数组,存放允许执行 ADMIN 权限命令的 peer_id)
|
||
ConfigField(
|
||
key="admin_users",
|
||
type="json",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=True,
|
||
title="管理员白名单",
|
||
description="允许执行 ADMIN 权限命令的 peer_id 列表,账户级配置。",
|
||
category="身份与权限",
|
||
),
|
||
# FR-29 入站提及策略(账户级,JSON,含 allowed_implicit_kinds 列表,
|
||
# 控制哪些隐式提及类型被视为"已提及",未配置时默认空策略)
|
||
ConfigField(
|
||
key="mention_policy",
|
||
type="json",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=True,
|
||
title="提及策略",
|
||
description="控制哪些隐式提及类型被视为'已提及',影响命令触发与会话路由。",
|
||
category="消息策略",
|
||
),
|
||
# FR-07 会话合并策略开关(默认禁用)
|
||
ConfigField(
|
||
key="merge_strategy_enabled",
|
||
type="bool",
|
||
required=False,
|
||
default=False,
|
||
hot_reloadable=True,
|
||
title="会话合并开关",
|
||
description="是否启用按策略自动合并会话。",
|
||
category="会话策略",
|
||
),
|
||
# FR-06 跨渠道身份策略(默认隔离,可选 association 开启跨渠道关联)
|
||
ConfigField(
|
||
key="cross_channel_identity_strategy",
|
||
type="str",
|
||
required=False,
|
||
default="isolation",
|
||
hot_reloadable=True,
|
||
title="跨渠道身份策略",
|
||
description="跨渠道身份关联策略:isolation(隔离)或 association(关联)。",
|
||
category="身份与权限",
|
||
),
|
||
# 可配置值(Task 30)
|
||
ConfigField(
|
||
key="command_prefix",
|
||
type="str",
|
||
required=False,
|
||
default="/",
|
||
hot_reloadable=True,
|
||
title="命令前缀",
|
||
description="命令触发前缀,默认为 '/'。",
|
||
category="命令与交互",
|
||
),
|
||
ConfigField(
|
||
key="fence_ttl_seconds",
|
||
type="int",
|
||
required=False,
|
||
default=120,
|
||
hot_reloadable=True,
|
||
title="围栏 TTL",
|
||
description="对话围栏(fence)的默认过期时间(秒)。",
|
||
category="命令与交互",
|
||
),
|
||
ConfigField(
|
||
key="streaming_min_chunk_interval_ms",
|
||
type="int",
|
||
required=False,
|
||
default=200,
|
||
hot_reloadable=True,
|
||
title="流式最小间隔",
|
||
description="流式响应相邻分块之间的最小间隔(毫秒)。",
|
||
category="流式与传输体验",
|
||
),
|
||
ConfigField(
|
||
key="streaming_ttl_seconds",
|
||
type="int",
|
||
required=False,
|
||
default=60,
|
||
hot_reloadable=True,
|
||
title="流式 TTL",
|
||
description="流式响应状态的最大保留时间(秒)。",
|
||
category="流式与传输体验",
|
||
),
|
||
ConfigField(
|
||
key="typing_ttl_ms",
|
||
type="int",
|
||
required=False,
|
||
default=10000,
|
||
hot_reloadable=True,
|
||
title="输入提示 TTL",
|
||
description="'正在输入'提示状态的最大持续时间(毫秒)。",
|
||
category="流式与传输体验",
|
||
),
|
||
ConfigField(
|
||
key="durability_policy_default",
|
||
type="str",
|
||
required=False,
|
||
default="required",
|
||
hot_reloadable=True,
|
||
title="默认持久化策略",
|
||
description="消息默认持久化策略:required / best_effort / none。",
|
||
category="可靠性",
|
||
),
|
||
# FR-24 分阶段 ACK 策略(PRD §FR-24)。
|
||
# 四阶段策略:after_record / after_agent_dispatch / after_persist / manual,
|
||
# 默认 after_agent_dispatch(平衡可靠性与响应速度)。
|
||
ConfigField(
|
||
key="ack_policy",
|
||
type="str",
|
||
required=False,
|
||
default="after_agent_dispatch",
|
||
hot_reloadable=True,
|
||
title="ACK 策略",
|
||
description="分阶段 ACK 策略:after_record / after_agent_dispatch / after_persist / manual。",
|
||
category="可靠性",
|
||
),
|
||
# 手动策略下插件忘记 ACK 时核心兜底超时(默认 60s)自动 ACK。
|
||
ConfigField(
|
||
key="ack_fallback_timeout_seconds",
|
||
type="int",
|
||
required=False,
|
||
default=60,
|
||
hot_reloadable=True,
|
||
title="ACK 兜底超时",
|
||
description="手动 ACK 策略下,插件忘记 ACK 时核心自动 ACK 的超时时间(秒)。",
|
||
category="可靠性",
|
||
),
|
||
# 传输引擎配置
|
||
ConfigField(
|
||
key="transport.stall_timeout_ms",
|
||
type="int",
|
||
required=False,
|
||
default=120000,
|
||
hot_reloadable=True,
|
||
title="传输停滞超时",
|
||
description="传输流判定为停滞的超时时间(毫秒)。",
|
||
category="传输引擎",
|
||
),
|
||
ConfigField(
|
||
key="transport.backoff_schedule",
|
||
type="str",
|
||
required=False,
|
||
default="1,2,5,10,30",
|
||
hot_reloadable=True,
|
||
title="传输退避序列",
|
||
description="传输重试的退避时间序列,逗号分隔的秒数列表。",
|
||
category="传输引擎",
|
||
),
|
||
ConfigField(
|
||
key="transport.backoff_jitter",
|
||
type="float",
|
||
required=False,
|
||
default=0.2,
|
||
hot_reloadable=True,
|
||
title="传输退避抖动",
|
||
description="传输重试退避的随机抖动系数。",
|
||
category="传输引擎",
|
||
),
|
||
# FR-22 Outbox 重试策略(OBX-POLICY-UPDATE),JSON 格式:
|
||
# {"max_retry": int, "ttl_seconds": int, "retry_backoff_schedule": [int, ...]}
|
||
# 由 OutboxHandler.updateRetryPolicy 双写到 ConfigPort(Redis),
|
||
# 支持跨请求 / 跨进程最终一致性。
|
||
ConfigField(
|
||
key="outbox_retry_policy",
|
||
type="json",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=True,
|
||
title="Outbox 重试策略",
|
||
description="出站消息重试策略,包含 max_retry / ttl_seconds / retry_backoff_schedule。",
|
||
category="可靠性",
|
||
),
|
||
# === 渠道用户与 Agent 交互链路优化(Task 6/7/8)===
|
||
# 身份解析置信度阈值(账户级,scope=ACCOUNT),低于此阈值的解析结果视为
|
||
# 未命中,进入 channel_guest 身份生成路径。缺口补齐:原 _getThreshold
|
||
# 使用硬编码默认值,现统一收敛至 CONFIG_SCHEMA。
|
||
ConfigField(
|
||
key="identity_confidence_threshold",
|
||
type="float",
|
||
required=False,
|
||
default=0.5,
|
||
hot_reloadable=True,
|
||
title="身份置信度阈值",
|
||
description="身份解析结果低于此阈值时视为未命中,进入 channel_guest 生成路径。",
|
||
category="身份与权限",
|
||
),
|
||
# 新建 Agent 的默认渠道访问级别(全局级,scope=GLOBAL),取值如
|
||
# "none" / "read" / "write" 等,由 Agent 创建流程读取。
|
||
ConfigField(
|
||
key="channel_access_default_level",
|
||
type="str",
|
||
required=False,
|
||
default="none",
|
||
hot_reloadable=True,
|
||
title="默认渠道访问级别",
|
||
description="新建 Agent 默认的渠道访问级别,如 none / read / write。",
|
||
category="身份与权限",
|
||
),
|
||
# 渠道访客身份置信度(全局级,scope=GLOBAL),channel_guest 身份生成时
|
||
# 使用此置信度,低于 identity_confidence_threshold 以避免被误判为
|
||
# 已解析身份。
|
||
ConfigField(
|
||
key="channel_guest_confidence",
|
||
type="float",
|
||
required=False,
|
||
default=0.3,
|
||
hot_reloadable=True,
|
||
title="访客身份置信度",
|
||
description="channel_guest 身份生成时使用的置信度,应低于身份置信度阈值。",
|
||
category="身份与权限",
|
||
),
|
||
# 是否启用管理员手动绑定功能(全局级,scope=GLOBAL),控制渠道用户与
|
||
# 统一身份的手动绑定入口是否可用。
|
||
ConfigField(
|
||
key="enable_channel_user_binding",
|
||
type="bool",
|
||
required=False,
|
||
default=True,
|
||
hot_reloadable=True,
|
||
title="手动绑定开关",
|
||
description="是否启用管理员手动绑定渠道用户与统一身份的功能入口。",
|
||
category="身份与权限",
|
||
),
|
||
# === 渠道账号运营流程优化(Task 14:契约层 CONFIG_SCHEMA 健康检查配置键)===
|
||
# 以下 2 个键均为渠道级(scope=CHANNEL),归属 ConfigPort(Redis 热重载,
|
||
# CHANNEL 业务策略体系),不得声明在 app_config。
|
||
# 凭证失效计数阈值。健康检查探活返回 401/403 时计入凭证失效计数,
|
||
# 达阈值后调聚合根 markFailed。窗口外(credential_failure_window_seconds)
|
||
# 重置计数。
|
||
ConfigField(
|
||
key="credential_failure_threshold",
|
||
type="int",
|
||
required=False,
|
||
default=3,
|
||
hot_reloadable=True,
|
||
title="凭证失效阈值",
|
||
description="健康检查中凭证失效计数的阈值。",
|
||
category="健康检查",
|
||
),
|
||
# 凭证失效计数窗口(秒)。窗口外的失效计数被重置,避免历史故障永久影响账号状态。
|
||
ConfigField(
|
||
key="credential_failure_window_seconds",
|
||
type="int",
|
||
required=False,
|
||
default=300,
|
||
hot_reloadable=True,
|
||
title="凭证失效窗口",
|
||
description="凭证失效计数的滑动窗口时长(秒)。",
|
||
category="健康检查",
|
||
),
|
||
# 审计日志保留策略(全局级,scope=GLOBAL)。JSON 格式:
|
||
# {"retention_days": int, "cleanup_interval_hours": int}
|
||
# 控制审计日志的保留天数与清理周期,由审计清理任务读取。
|
||
ConfigField(
|
||
key="audit_retention_policy",
|
||
type="json",
|
||
required=False,
|
||
default={"retention_days": 90, "cleanup_interval_hours": 24},
|
||
hot_reloadable=True,
|
||
title="审计保留策略",
|
||
description="审计日志保留天数与清理周期配置,JSON 格式。",
|
||
category="审计与登录",
|
||
),
|
||
# 扫码登录重定向 URI(全局级,scope=GLOBAL)。扫码登录成功后的前端跳转地址,
|
||
# 为空时使用默认跳转行为。
|
||
ConfigField(
|
||
key="qr_login_redirect_uri",
|
||
type="str",
|
||
required=False,
|
||
default="",
|
||
hot_reloadable=True,
|
||
title="扫码登录跳转地址",
|
||
description="扫码登录成功后的前端跳转地址。",
|
||
category="审计与登录",
|
||
),
|
||
# === 不可热更新字段(hot_reloadable=False)===
|
||
ConfigField(
|
||
key="webhook_port",
|
||
type="int",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="Webhook 端口",
|
||
description="渠道 Webhook 服务监听端口。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="webhook_secret",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="Webhook 密钥",
|
||
description="渠道 Webhook 签名验证密钥,敏感字段。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="tls_cert",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="TLS 证书",
|
||
description="TLS 证书内容,敏感字段。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="tls_key",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="TLS 私钥",
|
||
description="TLS 私钥内容,敏感字段。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="plugin_entry",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="插件入口",
|
||
description="插件入口模块路径。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="database_url",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="数据库地址",
|
||
description="业务数据库连接地址,敏感字段。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="redis_url",
|
||
type="str",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="Redis 地址",
|
||
description="Redis 连接地址,敏感字段。",
|
||
category="基础设施",
|
||
),
|
||
ConfigField(
|
||
key="transport.max_restart_attempts",
|
||
type="int",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
title="最大重启尝试",
|
||
description="传输进程异常后的最大重启次数。",
|
||
category="传输引擎",
|
||
),
|
||
ConfigField(
|
||
key="transport.graceful_shutdown_timeout_s",
|
||
type="float",
|
||
required=False,
|
||
default=10.0,
|
||
hot_reloadable=False,
|
||
title="优雅关闭超时",
|
||
description="传输进程优雅关闭的最大等待时间(秒)。",
|
||
category="传输引擎",
|
||
),
|
||
# === 渠道账号运营流程优化(Task 3:契约层 CONFIG_SCHEMA 凭证配置键)===
|
||
# 以下 3 个键均为账户级(scope=ACCOUNT),归属 ConfigPort(Redis 热重载,
|
||
# CHANNEL 业务策略/toggles/TTLs 体系),不得声明在 app_config。
|
||
# 凭证包,敏感字段加密存储。由 CredentialService 唯一写入入口维护,
|
||
# 包含 bot_token/app_secret/user_access_token 等渠道认证凭证。
|
||
ConfigField(
|
||
key="credentials",
|
||
type="dict",
|
||
required=False,
|
||
default=None,
|
||
hot_reloadable=False,
|
||
sensitive=True,
|
||
title="渠道凭证包",
|
||
description="渠道认证凭证集合,敏感字段。",
|
||
category="凭证与登录态",
|
||
),
|
||
# 登录态:unlogged/logging_in/logged_in/logout_failed。由 QrLoginService
|
||
# 通过 ConfigPort 维护,区分扫码会话状态与最终凭证落库状态。
|
||
ConfigField(
|
||
key="login_status",
|
||
type="str",
|
||
required=False,
|
||
default="unlogged",
|
||
hot_reloadable=False,
|
||
title="登录状态",
|
||
description="当前账户扫码登录状态。",
|
||
category="凭证与登录态",
|
||
),
|
||
# 凭证版本号,每次 rotateCredentials 自增。用于乐观锁控制与缓存失效判定。
|
||
ConfigField(
|
||
key="credential_version",
|
||
type="int",
|
||
required=False,
|
||
default=0,
|
||
hot_reloadable=False,
|
||
title="凭证版本",
|
||
description="凭证轮换版本号,用于乐观锁与缓存失效。",
|
||
category="凭证与登录态",
|
||
),
|
||
# FR17-P0-3 已应用迁移列表(ACCOUNT 作用域,target=channel_type 或
|
||
# {channel_type}:{account_id})。由 PluginLifecycleManager 在插件 onStart
|
||
# 成功后追加 manifest.version 标记配置已加载,DoctorService 只读不写。
|
||
# hot_reloadable=False:非业务策略,启动期写入,无需热更新。
|
||
# default=[] 让首次加载时 ConfigPort.get 返回空列表而非 NotFoundError,
|
||
# 避免 PluginLifecycleManager 与 DoctorService 的 catch 块接不到异常。
|
||
ConfigField(
|
||
key="applied_migrations",
|
||
type="json",
|
||
required=False,
|
||
default=[],
|
||
hot_reloadable=False,
|
||
title="已应用迁移",
|
||
description="账户已应用的插件迁移版本列表。",
|
||
category="凭证与登录态",
|
||
),
|
||
)
|
||
|
||
# 可热更新的配置项键集合(FR-37),从 CONFIG_SCHEMA 派生。
|
||
HOT_RELOADABLE_KEYS = frozenset(f.key for f in CONFIG_SCHEMA if f.hot_reloadable)
|
||
|
||
# 不可热更新的配置项键集合(FR-37),从 CONFIG_SCHEMA 派生。
|
||
NON_HOT_RELOADABLE_KEYS = frozenset(f.key for f in CONFIG_SCHEMA if not f.hot_reloadable)
|
||
|
||
__all__ = ["CONFIG_SCHEMA", "HOT_RELOADABLE_KEYS", "NON_HOT_RELOADABLE_KEYS"]
|