

























@@ -10,9 +10,11 @@ import {
1010recoverConfigFromLastKnownGood,
1111recoverConfigFromJsonRootSuffix,
1212shouldAttemptLastKnownGoodRecovery,
13+validateConfigObjectWithPlugins,
1314writeConfigFile,
1415} from "../config/config.js";
1516import { formatConfigIssueLines } from "../config/issue-format.js";
17+import { asResolvedSourceConfig, materializeRuntimeConfig } from "../config/materialize.js";
1618import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
1719import { isTruthyEnvValue } from "../infra/env.js";
1820import {
@@ -56,20 +58,122 @@ type GatewayStartupConfigOverrides = {
5658export type GatewayStartupConfigSnapshotLoadResult = {
5759snapshot: ConfigFileSnapshot;
5860wroteConfig: boolean;
61+degradedProviderApi?: boolean;
5962};
606364+const MODEL_PROVIDER_API_PATH_RE = /^models\.providers\.([^.]+)\.api$/;
65+const MODEL_PROVIDER_MODEL_API_PATH_RE = /^models\.providers\.([^.]+)\.models\.\d+\.api$/;
66+67+function resolveInvalidModelProviderApiIssueProviderId(issue: {
68+path: string;
69+message: string;
70+}): string | null {
71+if (!issue.message.startsWith("Invalid option:")) {
72+return null;
73+}
74+const providerMatch =
75+issue.path.match(MODEL_PROVIDER_API_PATH_RE) ??
76+issue.path.match(MODEL_PROVIDER_MODEL_API_PATH_RE);
77+return providerMatch?.[1] ?? null;
78+}
79+80+function cloneConfigWithoutModelProviders(
81+config: OpenClawConfig,
82+providerIds: ReadonlySet<string>,
83+): OpenClawConfig {
84+const providers = config.models?.providers;
85+if (!providers) {
86+return config;
87+}
88+let changed = false;
89+const nextProviders = { ...providers };
90+for (const providerId of providerIds) {
91+if (!Object.hasOwn(nextProviders, providerId)) {
92+continue;
93+}
94+delete nextProviders[providerId];
95+changed = true;
96+}
97+if (!changed) {
98+return config;
99+}
100+return {
101+ ...config,
102+models: {
103+ ...config.models,
104+providers: nextProviders,
105+},
106+};
107+}
108+109+function resolveGatewayStartupConfigWithoutInvalidModelProviders(params: {
110+snapshot: ConfigFileSnapshot;
111+log: GatewayStartupLog;
112+}): ConfigFileSnapshot | null {
113+if (params.snapshot.valid || params.snapshot.legacyIssues.length > 0) {
114+return null;
115+}
116+const providerIds = new Set<string>();
117+for (const issue of params.snapshot.issues) {
118+const providerId = resolveInvalidModelProviderApiIssueProviderId(issue);
119+if (!providerId) {
120+return null;
121+}
122+providerIds.add(providerId);
123+}
124+if (providerIds.size === 0) {
125+return null;
126+}
127+128+const prunedSourceConfig = cloneConfigWithoutModelProviders(
129+params.snapshot.sourceConfig,
130+providerIds,
131+);
132+const validated = validateConfigObjectWithPlugins(prunedSourceConfig);
133+if (!validated.ok) {
134+return null;
135+}
136+const runtimeConfig = materializeRuntimeConfig(validated.config, "load");
137+for (const providerId of providerIds) {
138+params.log.warn(
139+`gateway: skipped model provider ${providerId}; configured provider api is invalid. Run "openclaw doctor --fix" to repair the config.`,
140+);
141+}
142+return {
143+ ...params.snapshot,
144+sourceConfig: asResolvedSourceConfig(validated.config),
145+resolved: asResolvedSourceConfig(validated.config),
146+valid: true,
147+ runtimeConfig,
148+config: runtimeConfig,
149+issues: [],
150+warnings: validated.warnings,
151+};
152+}
153+61154export async function loadGatewayStartupConfigSnapshot(params: {
62155minimalTestGateway: boolean;
63156log: GatewayStartupLog;
64157}): Promise<GatewayStartupConfigSnapshotLoadResult> {
65158let configSnapshot = await readConfigFileSnapshot();
66159let wroteConfig = false;
160+let degradedStartupConfig = false;
67161if (configSnapshot.legacyIssues.length > 0 && isNixMode) {
68162throw new Error(
69163"Legacy config entries detected while running in Nix mode. Update your Nix config to the latest schema and restart.",
70164);
71165}
72166if (configSnapshot.exists) {
167+if (!configSnapshot.valid) {
168+const providerApiPrunedSnapshot = resolveGatewayStartupConfigWithoutInvalidModelProviders({
169+snapshot: configSnapshot,
170+log: params.log,
171+});
172+if (providerApiPrunedSnapshot) {
173+degradedStartupConfig = true;
174+configSnapshot = providerApiPrunedSnapshot;
175+}
176+}
73177if (!configSnapshot.valid) {
74178const canRecoverFromLastKnownGood = shouldAttemptLastKnownGoodRecovery(configSnapshot);
75179const recovered = canRecoverFromLastKnownGood
@@ -109,11 +213,16 @@ export async function loadGatewayStartupConfigSnapshot(params: {
109213assertValidGatewayStartupConfigSnapshot(configSnapshot, { includeDoctorHint: true });
110214}
111215112-const autoEnable = params.minimalTestGateway
113- ? { config: configSnapshot.config, changes: [] as string[] }
114- : applyPluginAutoEnable({ config: configSnapshot.config, env: process.env });
216+const autoEnable =
217+params.minimalTestGateway || degradedStartupConfig
218+ ? { config: configSnapshot.config, changes: [] as string[] }
219+ : applyPluginAutoEnable({ config: configSnapshot.config, env: process.env });
115220if (autoEnable.changes.length === 0) {
116-return { snapshot: configSnapshot, wroteConfig };
221+return {
222+snapshot: configSnapshot,
223+ wroteConfig,
224+ ...(degradedStartupConfig ? { degradedProviderApi: true } : {}),
225+};
117226}
118227119228try {
@@ -128,7 +237,11 @@ export async function loadGatewayStartupConfigSnapshot(params: {
128237params.log.warn(`gateway: failed to persist plugin auto-enable changes: ${String(err)}`);
129238}
130239131-return { snapshot: configSnapshot, wroteConfig };
240+return {
241+snapshot: configSnapshot,
242+ wroteConfig,
243+ ...(degradedStartupConfig ? { degradedProviderApi: true } : {}),
244+};
132245}
133246134247export function createRuntimeSecretsActivator(params: {
@@ -226,6 +339,7 @@ export async function prepareGatewayStartupConfig(params: {
226339authOverride?: GatewayAuthConfig;
227340tailscaleOverride?: GatewayTailscaleConfig;
228341activateRuntimeSecrets: ActivateRuntimeSecrets;
342+persistStartupAuth?: boolean;
229343}): Promise<Awaited<ReturnType<typeof ensureGatewayStartupAuth>>> {
230344assertValidGatewayStartupConfigSnapshot(params.configSnapshot);
231345@@ -262,7 +376,7 @@ export async function prepareGatewayStartupConfig(params: {
262376env: process.env,
263377authOverride: preflightAuthOverride,
264378tailscaleOverride: params.tailscaleOverride,
265-persist: true,
379+persist: params.persistStartupAuth ?? true,
266380baseHash: params.configSnapshot.hash,
267381});
268382const runtimeStartupConfig = applyGatewayAuthOverridesForStartupPreflight(authBootstrap.cfg, {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。