生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~210k tokens,输出 ~8k tokens(本节)
OpenClaw 并非从零诞生——它经历了 moldbot → moltbot → clawdbot → openclaw 的多次更名与架构重组,配置结构也随之不断演进。早期的顶级 whatsapp、telegram 配置键被收编到 channels.whatsapp、channels.telegram;早期的 agent.model 字符串被拆分为 agents.defaults.model.primary 加 fallbacks 数组;routing 下的各种子配置被分散到 agents、tools、messages 等更语义化的位置。为了让老用户无痛升级,OpenClaw 在配置加载流水线中内置了一套自动迁移系统——本节剖析其设计与实现。
23.4.1 迁移框架(src/config/legacy.ts)
遗留配置处理由两个互补的子系统组成:
扫描配置,发现使用了旧格式的路径,返回人类可读的警告消息
两者可以独立使用:检测用于在 Web 控制台或 CLI 中显示升级提示;迁移则在配置加载流水线中自动执行。
检测:findLegacyConfigIssues
检测函数遍历一组预定义的规则(LEGACY_CONFIG_RULES),对每条规则的路径进行查找。如果对应路径存在值且(可选的)匹配条件成立,就记录一条问题:
// src/config/legacy.ts
export function findLegacyConfigIssues(raw: unknown): LegacyConfigIssue[] {
if (!raw || typeof raw !== "object") return [];
const root = raw as Record<string, unknown>;
const issues: LegacyConfigIssue[] = [];
for (const rule of LEGACY_CONFIG_RULES) {
// 逐层遍历路径
let cursor: unknown = root;
for (const key of rule.path) {
if (!cursor || typeof cursor !== "object") {
cursor = undefined;
break;
}
cursor = (cursor as Record<string, unknown>)[key];
}
// 路径存在且匹配条件满足 → 记录问题
if (cursor !== undefined && (!rule.match || rule.match(cursor, root))) {
issues.push({ path: rule.path.join("."), message: rule.message });
}
}
return issues;
}
迁移:applyLegacyMigrations
迁移函数使用 structuredClone 深拷贝原始配置,然后依次执行所有迁移规则:
衍生解释:structuredClone 是浏览器和 Node.js(v17+)原生提供的深拷贝 API,比 JSON.parse(JSON.stringify(obj)) 更强大——它能正确处理 Date、RegExp、Map、Set、循环引用等类型。在这里使用深拷贝至关重要:迁移函数会直接修改对象结构(删除键、移动值),如果不拷贝就会破坏原始输入。
检测规则和迁移规则的类型定义在 legacy.shared.ts 中:
match 是一个可选的谓词函数,用于区分同一路径下不同类型值的处理方式。例如 agent.model 既可以是字符串(旧格式)也可以是对象(新格式),只有字符串值才需要迁移:
入口函数:migrateLegacyConfig
legacy-migrate.ts 提供了完整的迁移入口——迁移后立即验证配置有效性:
这个"迁移 + 验证"的组合确保了迁移结果的正确性——如果自动迁移无法完全修复配置(比如涉及到需要人工决策的情况),函数会返回 null 并附上提示信息。
legacy.shared.ts 还提供了一组实用的辅助函数,供迁移规则使用:
mergeMissing 的语义是"只填补缺失"——它不会覆盖目标中已有的值。这在迁移中很重要:用户可能同时拥有新旧两种格式的配置(比如既有 whatsapp 又有 channels.whatsapp),mergeMissing 确保新格式的值不会被旧格式覆盖。
23.4.2 迁移规则(src/config/legacy.rules.ts)
LEGACY_CONFIG_RULES 数组定义了 25+ 条检测规则,覆盖了 OpenClaw 历史上所有重大的配置结构变更。按类别分组如下:
渠道迁移(7 条):
路由拆解(8 条):
channels.whatsapp.allowFrom
routing.groupChat.requireMention
channels.*.groups."*".requireMention
routing.groupChat.mentionPatterns
messages.groupChat.mentionPatterns
Agent 配置重组(7 条):
agents.defaults.model.primary/fallbacks
agents.defaults.imageModel.primary/fallbacks
agents.defaults.models.*.alias
agents.defaults.model.fallbacks
其他迁移:
channels.telegram.groups."*".requireMention
23.4.3 分阶段迁移(legacy.migrations.part-1/2/3.ts)
迁移规则按复杂度和依赖关系拆分为三个阶段,通过 legacy.migrations.ts 汇总:
顺序至关重要——Part 1 先将渠道配置归位,Part 2 才能正确处理 Agent 路由(因为路由迁移可能引用渠道),Part 3 最后清理 agent.* 残留到 agents.defaults。
Part 1 包含 9 条迁移规则,主要处理字段重命名和位置移动:
规则 1:bindings.match.provider → bindings.match.channel
早期版本使用 provider 来标识消息来源(WhatsApp、Telegram 等),后来统一为 channel(渠道)。迁移遍历 bindings 数组中的每个条目:
规则 5:顶级渠道 → channels.*
这是最常见的迁移——将 whatsapp、telegram 等顶级键移入 channels 命名空间:
规则 7:routing.groupChat.requireMention 扇出
这个迁移比较特殊——单一配置值需要"扇出"到多个渠道的群聊配置中:
注意 requireExisting 选项——对于 WhatsApp,只有在用户已经配置了 WhatsApp 的情况下才迁移 requireMention,避免为未使用的渠道创建空配置。
Part 2 包含 3 条迁移规则,处理最复杂的模型配置和 Agent 路由迁移。
模型配置迁移(agent.model-config-v2)
这是整个迁移系统中最复杂的规则。早期版本中,模型配置是一组扁平的字段:
需要迁移为结构化格式:
迁移过程分为四步:(1) 收集所有涉及的模型名称并在 models 映射中创建条目;(2) 将 modelAliases 的别名关系嵌入到对应模型的 alias 字段;(3) 构建 model.primary/fallbacks 和 imageModel.primary/fallbacks 结构;(4) 清理旧字段。
Agent 路由迁移(routing.agents-v2)
将 routing.agents 中按 Agent ID 分组的配置迁移到 agents.list 数组,同时处理 mentionPatterns、groupChat、sandbox.tools 等子配置的位置调整。
Part 3:Agent 默认值与工具
Part 3 包含 5 条收尾性质的迁移规则:
agent.defaults-v2:最终清理
这条规则执行 agent.* → agents.defaults 的最终迁移,同时将工具相关配置分流到 tools.*:
identity->agents.list:身份配置归属
将顶级 identity 移到默认 Agent 的配置中。确定"默认 Agent"使用 resolveDefaultAgentIdFromRaw——它按优先级查找:(1) agents.list 中 default: true 的条目;(2) routing.defaultAgentId;(3) 列表中的第一个条目;(4) 兜底值 "main"。
其他 Part 3 规则:
auth.anthropic-claude-cli-mode-oauth
messages.tts.enabled->auto
enabled: true → auto: "always",enabled: false → auto: "off"
从源码中可以总结出以下设计原则:
幂等性:每条规则都先检查目标位置是否已有值。如果已有值,则跳过迁移(或仅删除旧键),确保多次执行结果一致。
只填补不覆盖:mergeMissing 语义确保用户在新位置手动设置的值不会被旧值覆盖。
完整日志:每条规则执行后都会向 changes 数组追加人类可读的变更描述,便于用户了解自动迁移做了什么。
渐进清理:迁移后如果对象变为空(如 routing 下的所有键都被迁走),则删除空对象,保持配置整洁。
顺序依赖:Part 1 → Part 2 → Part 3 的顺序确保前置迁移完成后再执行依赖它们的迁移。
双轨系统:遗留配置处理分为"检测"(findLegacyConfigIssues,生成警告)和"迁移"(applyLegacyMigrations,自动修复)两个独立子系统。
深拷贝保护:迁移在 structuredClone 产生的副本上操作,不影响原始输入。
25+ 检测规则覆盖了渠道迁移、路由拆解、Agent 配置重组、工具重命名等所有历史变更。
三阶段迁移(Part 1/2/3)按依赖关系排序:基础迁移 → 模型与路由 → Agent 默认值与工具。
幂等设计确保迁移可以安全地多次执行,不会破坏已经迁移过的配置。
mergeMissing 语义保证"用户手动设置的新格式配置"不会被旧格式值覆盖。
迁移后验证(migrateLegacyConfig)确保迁移结果通过 Zod 验证,无效则提示手动修复。