


























@@ -5,6 +5,7 @@ import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
55import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js";
66import {
77createConfigIO,
8+registerConfigWriteListener,
89resetConfigRuntimeState,
910setRuntimeConfigSnapshot,
1011writeConfigFile,
@@ -532,4 +533,92 @@ describe("config io write", () => {
532533}
533534});
534535});
536+537+it("notifies in-process reloaders with resolved source config when persisted env refs are restored", async () => {
538+await withSuiteHome(async (home) => {
539+const configPath = path.join(home, ".openclaw", "openclaw.json");
540+const previousConfigPath = process.env.OPENCLAW_CONFIG_PATH;
541+const previousGatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN;
542+process.env.OPENCLAW_CONFIG_PATH = configPath;
543+process.env.OPENCLAW_GATEWAY_TOKEN = "gateway-token-runtime";
544+await fs.mkdir(path.dirname(configPath), { recursive: true });
545+await fs.writeFile(
546+configPath,
547+`${JSON.stringify(
548+ {
549+ gateway: {
550+ mode: "local",
551+ auth: { mode: "token", token: "${OPENCLAW_GATEWAY_TOKEN}" },
552+ },
553+ agents: { defaults: { model: { primary: "openai/gpt-5.4" } } },
554+ },
555+ null,
556+ 2,
557+ )}\n`,
558+"utf-8",
559+);
560+const observedSources: unknown[] = [];
561+const unsubscribe = registerConfigWriteListener((event) => {
562+observedSources.push(event.sourceConfig);
563+});
564+565+try {
566+setRuntimeConfigSnapshot(
567+{
568+gateway: {
569+mode: "local",
570+auth: { mode: "token", token: "gateway-token-runtime" },
571+},
572+agents: { defaults: { model: { primary: "openai/gpt-5.4" } } },
573+},
574+{
575+gateway: {
576+mode: "local",
577+auth: { mode: "token", token: "gateway-token-runtime" },
578+},
579+agents: { defaults: { model: { primary: "openai/gpt-5.4" } } },
580+},
581+);
582+583+await writeConfigFile({
584+gateway: {
585+mode: "local",
586+auth: { mode: "token", token: "gateway-token-runtime" },
587+},
588+agents: { defaults: { model: { primary: "openrouter/anthropic/claude-sonnet-4.6" } } },
589+});
590+591+expect(JSON.parse(await fs.readFile(configPath, "utf-8"))).toMatchObject({
592+gateway: {
593+auth: { token: "${OPENCLAW_GATEWAY_TOKEN}" },
594+},
595+});
596+expect(observedSources).toEqual([
597+expect.objectContaining({
598+gateway: {
599+mode: "local",
600+auth: { mode: "token", token: "gateway-token-runtime" },
601+},
602+agents: {
603+defaults: {
604+model: { primary: "openrouter/anthropic/claude-sonnet-4.6" },
605+},
606+},
607+}),
608+]);
609+} finally {
610+unsubscribe();
611+if (previousConfigPath === undefined) {
612+delete process.env.OPENCLAW_CONFIG_PATH;
613+} else {
614+process.env.OPENCLAW_CONFIG_PATH = previousConfigPath;
615+}
616+if (previousGatewayToken === undefined) {
617+delete process.env.OPENCLAW_GATEWAY_TOKEN;
618+} else {
619+process.env.OPENCLAW_GATEWAY_TOKEN = previousGatewayToken;
620+}
621+}
622+});
623+});
535624});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。