配置系统架构
Moltbot 的配置加载、验证、迁移和热重载机制
概述
配置系统是 Moltbot 的基础组件,负责加载、验证、管理配置文件。支持环境变量替换、包含机制、遗留配置迁移和运行时热重载。
设计目标
- 层次结构: 清晰的配置层次和类型安全
- 环境变量: 支持
${VAR}语法替换 - 包含机制: 支持
$include指令合并多个文件 - 迁移系统: 自动迁移遗留配置
- 热重载: 部分配置支持无需重启的热重载
配置结构层次
主配置类型
文件: src/config/types.ts
MoltbotConfig
├── meta // 元数据(版本、时间戳)
├── env // 环境变量配置
│ ├── shellEnv // Shell 环境变量加载
│ └── vars // 自定义环境变量
├── wizard // 向导状态
├── diagnostics // 诊断配置
├── logging // 日志配置
├── update // 更新通道配置
├── browser // 浏览器控制配置
├── ui // UI 配置
├── auth // 认证配置
├── models // 模型目录
├── nodeHost // 节点主机配置
├── agents // 代理配置
│ ├── defaults // 默认值
│ └── list // 代理列表
├── tools // 工具配置
├── bindings // 绑定配置
├── broadcast // 广播配置
├── audio // 音频配置
├── messages // 消息配置
├── commands // 命令配置
├── approvals // 审批配置
├── session // 会话配置
├── cron // Cron 任务配置
├── hooks // 钩子配置
├── web // Web 提供商配置
├── channels // 消息通道配置
├── discovery // 发现配置
├── canvasHost // Canvas 主机配置
├── talk // Talk 语音配置
├── gateway // 网关配置
├── skills // 技能配置
└── plugins // 插件配置
配置加载流程
加载流程图
配置路径解析
文件: src/config/paths.ts
// 路径解析优先级:
// 1. MOLTBOT_CONFIG_PATH (新)
// 2. CLAWDBOT_CONFIG_PATH (遗留)
// 3. $MOLTBOT_STATE_DIR/moltbot.json
// 4. $CLAWDBOT_STATE_DIR/moltbot.json
// 5. ~/.moltbot/moltbot.json
// 6. ~/.clawdbot/moltbot.json
export function resolveConfigPath(
env: NodeJS.ProcessEnv,
stateDir: string,
homedir: () => string
): string
配置包含机制
文件: src/config/includes.ts
// 支持 $include 指令:
{
"$include": "./base.json5" // 单文件
"$include": ["./a.json5", "./b.json5"] // 多文件合并
}
// 特性:
// - 深度合并 (数组连接, 对象递归合并)
// - 循环引用检测 (CircularIncludeError)
// - 最大深度限制 (MAX_INCLUDE_DEPTH = 10)
// - 支持兄弟键合并
环境变量替换
文件: src/config/env/env-substitution.ts
// 语法: ${VAR_NAME}
{
apiKey: "${OPENAI_API_KEY}",
token: "${CLAWDBOT_GATEWAY_TOKEN}"
}
// 特性:
// - 仅匹配大写环境变量: [A-Z_][A-Z0-9_]*
// - 转义: $${VAR} -> ${VAR}
// - 缺失时抛出 MissingEnvVarError
// - config.env 中的变量可被 ${VAR} 引用
配置管理
配置保存
文件: src/config/io.ts
async function writeConfigFile(cfg: MoltbotConfig) {
// 1. 验证配置
const validated = validateConfigObjectWithPlugins(cfg);
if (!validated.ok) throw new Error(...);
// 2. 创建目录 (权限 0o700)
await deps.fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });
// 3. 添加版本元数据
const json = JSON.stringify(stampConfigVersion(cfg), null, 2);
// 4. 写入临时文件
const tmp = {path}.{pid}.{uuid}.tmp;
await deps.fs.promises.writeFile(tmp, json, { mode: 0o600 });
// 5. 旋转备份 (保留 5 个备份)
await rotateConfigBackups(configPath);
// 6. 原子替换
await deps.fs.promises.rename(tmp, configPath);
}
配置快照和哈希
export type ConfigFileSnapshot = {
path: string;
exists: boolean;
raw: string | null; // 原始内容
parsed: unknown; // 解析后内容
valid: boolean; // 是否验证通过
config: MoltbotConfig; // 最终配置
hash: string; // SHA256 哈希
issues: ConfigValidationIssue[];
warnings: ConfigIssue[];
legacyIssues: LegacyConfigIssue[];
};
function hashConfigRaw(raw: string | null): string {
return crypto.createHash("sha256").update(raw ?? "").digest("hex");
}
配置缓存
// 内存缓存 (默认 200ms)
const DEFAULT_CONFIG_CACHE_MS = 200;
let configCache: {
configPath: string;
expiresAt: number;
config: MoltbotConfig;
} | null = null;
// 可通过环境变量禁用:
// CLAWDBOT_DISABLE_CONFIG_CACHE=1
// CLAWDBOT_CONFIG_CACHE_MS=0
验证和迁移
验证流程
文件: src/config/validation.ts
export function validateConfigObjectWithPlugins(raw: unknown) {
// 1. 基础 Zod 验证
const validated = MoltbotSchema.safeParse(raw);
if (!validated.success) return { ok: false, issues: ... };
// 2. 查找重复代理目录
const duplicates = findDuplicateAgentDirs(config);
if (duplicates.length > 0) return { ok: false, issues: ... };
// 3. 验证头像路径
const avatarIssues = validateIdentityAvatar(config);
if (avatarIssues.length > 0) return { ok: false, issues: ... };
// 4. 插件验证
// - 检查插件是否存在
// - 验证插件配置 Schema
// - 验证内存槽位
// - 验证通道 ID
// 5. 通道验证
// - 验证心跳目标
return { ok: true, config, warnings: [] };
}
遗留配置迁移
文件: src/config/legacy.migrations.ts
// 迁移分为 3 部分
export const LEGACY_CONFIG_MIGRATIONS = [
...LEGACY_CONFIG_MIGRATIONS_PART_1, // 基础重命名
...LEGACY_CONFIG_MIGRATIONS_PART_2, // 复杂重构
...LEGACY_CONFIG_MIGRATIONS_PART_3, // 细节清理
];
// 示例迁移:
{
id: "providers->channels",
describe: "Move provider config sections to channels.*",
apply: (raw, changes) => {
// 将 whatsapp, telegram, discord 等移到 channels.* 下
const legacyKeys = ["whatsapp", "telegram", "discord", ...];
for (const key of legacyKeys) {
if (raw[key]) {
raw.channels[key] = raw[key];
delete raw[key];
changes.push(`Moved ${key} → channels.${key}.`);
}
}
}
}
遗留配置规则
文件: src/config/legacy.rules.ts
// 用于检测未迁移的遗留配置
export const LEGACY_CONFIG_RULES = [
{
path: ["whatsapp"],
message: "whatsapp config moved to channels.whatsapp (auto-migrated on load).",
},
{
path: ["routing", "allowFrom"],
message: "routing.allowFrom was removed; use channels.whatsapp.allowFrom instead...",
},
// ...
];
热重载机制
重载模式
文件: src/gateway/config-reload.ts
type GatewayReloadMode = "off" | "restart" | "hot" | "hybrid";
const DEFAULT_RELOAD_SETTINGS = {
mode: "hybrid", // 推荐
debounceMs: 300, // 防抖延迟
};
重载决策流程
重载规则
// 基础规则
const BASE_RELOAD_RULES = [
{ prefix: "hooks.gmail", kind: "hot", actions: ["restart-gmail-watcher"] },
{ prefix: "hooks", kind: "hot", actions: ["reload-hooks"] },
{ prefix: "agents.defaults.heartbeat", kind: "hot", actions: ["restart-heartbeat"] },
{ prefix: "cron", kind: "hot", actions: ["restart-cron"] },
{ prefix: "browser", kind: "hot", actions: ["restart-browser-control"] },
// 忽略的配置
{ prefix: "gateway.remote", kind: "none" },
{ prefix: "gateway.reload", kind: "none" },
];
// 重启触发
const BASE_RELOAD_RULES_TAIL = [
{ prefix: "plugins", kind: "restart" },
{ prefix: "gateway", kind: "restart" },
{ prefix: "discovery", kind: "restart" },
{ prefix: "canvasHost", kind: "restart" },
];
运行时覆盖
覆盖机制
文件: src/config/runtime-overrides.ts
let overrides: { [key: string]: unknown } = {};
// 设置覆盖
export function setConfigOverride(pathRaw: string, value: unknown) {
const parsed = parseConfigPath(pathRaw);
setConfigValueAtPath(overrides, parsed.path, value);
}
// 应用覆盖 (在所有加载流程最后)
export function applyConfigOverrides(cfg: MoltbotConfig): MoltbotConfig {
if (!overrides || Object.keys(overrides).length === 0) return cfg;
return mergeOverrides(cfg, overrides);
}
覆盖优先级
优先级顺序 (从低到高):
- 配置文件 (moltbot.json)
$include包含的文件config.env定义的变量 (添加到 process.env)- 环境变量替换 (${VAR})
- 运行时覆盖 (setConfigOverride)
配置差异检测
// 深度对比配置
export function diffConfigPaths(prev: unknown, next: unknown, prefix = ""): string[] {
if (prev === next) return [];
if (isPlainObject(prev) && isPlainObject(next)) {
const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);
for (const key of keys) {
const childPaths = diffConfigPaths(prev[key], next[key], `${prefix}.${key}`);
paths.push(...childPaths);
}
return paths;
}
return [prefix || "<root>"];
}
代码路径引用
| 功能 | 文件路径 |
|---|---|
| 主类型定义 | src/config/types.ts |
| 配置加载 | src/config/io.ts |
| 配置验证 | src/config/validation.ts |
| Zod Schema | src/config/zod-schema.ts |
| 路径解析 | src/config/paths.ts |
| 包含机制 | src/config/includes.ts |
| 环境变量替换 | src/config/env/env-substitutional.ts |
| 遗留迁移 | src/config/legacy.migrations.ts |
| 遗留规则 | src/config/legacy.rules.ts |
| 运行时覆盖 | src/config/runtime-overrides.ts |
| 热重载 | src/gateway/config-reload.ts |