Skip to content

Commit c71ee4d

Browse files
committed
refactor: split doctor and gateway test helpers
1 parent 267ebc3 commit c71ee4d

8 files changed

Lines changed: 466 additions & 411 deletions
Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1 @@
1-
import type { OpenClawConfig } from "../config/config.js";
2-
import { runPluginSetupConfigMigrations } from "../plugins/setup-registry.js";
3-
import {
4-
normalizeLegacyBrowserConfig,
5-
normalizeLegacyCrossContextMessageConfig,
6-
normalizeLegacyMediaProviderOptions,
7-
normalizeLegacyMistralModelMaxTokens,
8-
normalizeLegacyNanoBananaSkill,
9-
normalizeLegacyTalkConfig,
10-
seedMissingDefaultAccountsFromSingleAccountBase,
11-
} from "./doctor/shared/legacy-config-core-normalizers.js";
12-
import { migrateLegacyWebFetchConfig } from "./doctor/shared/legacy-web-fetch-migrate.js";
13-
import { migrateLegacyWebSearchConfig } from "./doctor/shared/legacy-web-search-migrate.js";
14-
import { migrateLegacyXSearchConfig } from "./doctor/shared/legacy-x-search-migrate.js";
15-
16-
export function normalizeCompatibilityConfigValues(cfg: OpenClawConfig): {
17-
config: OpenClawConfig;
18-
changes: string[];
19-
} {
20-
const changes: string[] = [];
21-
let next = seedMissingDefaultAccountsFromSingleAccountBase(cfg, changes);
22-
next = normalizeLegacyBrowserConfig(next, changes);
23-
24-
const setupMigration = runPluginSetupConfigMigrations({
25-
config: next,
26-
});
27-
if (setupMigration.changes.length > 0) {
28-
next = setupMigration.config;
29-
changes.push(...setupMigration.changes);
30-
}
31-
32-
for (const migrate of [
33-
migrateLegacyWebSearchConfig,
34-
migrateLegacyWebFetchConfig,
35-
migrateLegacyXSearchConfig,
36-
]) {
37-
const migrated = migrate(next);
38-
if (migrated.changes.length === 0) {
39-
continue;
40-
}
41-
next = migrated.config;
42-
changes.push(...migrated.changes);
43-
}
44-
45-
next = normalizeLegacyNanoBananaSkill(next, changes);
46-
next = normalizeLegacyTalkConfig(next, changes);
47-
next = normalizeLegacyCrossContextMessageConfig(next, changes);
48-
next = normalizeLegacyMediaProviderOptions(next, changes);
49-
next = normalizeLegacyMistralModelMaxTokens(next, changes);
50-
51-
return { config: next, changes };
52-
}
1+
export { normalizeCompatibilityConfigValues } from "./doctor/shared/legacy-config-core-migrate.js";
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { OpenClawConfig } from "../../../config/config.js";
2+
import { runPluginSetupConfigMigrations } from "../../../plugins/setup-registry.js";
3+
import {
4+
normalizeLegacyBrowserConfig,
5+
normalizeLegacyCrossContextMessageConfig,
6+
normalizeLegacyMediaProviderOptions,
7+
normalizeLegacyMistralModelMaxTokens,
8+
normalizeLegacyNanoBananaSkill,
9+
normalizeLegacyTalkConfig,
10+
seedMissingDefaultAccountsFromSingleAccountBase,
11+
} from "./legacy-config-core-normalizers.js";
12+
import { migrateLegacyWebFetchConfig } from "./legacy-web-fetch-migrate.js";
13+
import { migrateLegacyWebSearchConfig } from "./legacy-web-search-migrate.js";
14+
import { migrateLegacyXSearchConfig } from "./legacy-x-search-migrate.js";
15+
16+
export function normalizeCompatibilityConfigValues(cfg: OpenClawConfig): {
17+
config: OpenClawConfig;
18+
changes: string[];
19+
} {
20+
const changes: string[] = [];
21+
let next = seedMissingDefaultAccountsFromSingleAccountBase(cfg, changes);
22+
next = normalizeLegacyBrowserConfig(next, changes);
23+
24+
const setupMigration = runPluginSetupConfigMigrations({
25+
config: next,
26+
});
27+
if (setupMigration.changes.length > 0) {
28+
next = setupMigration.config;
29+
changes.push(...setupMigration.changes);
30+
}
31+
32+
for (const migrate of [
33+
migrateLegacyWebSearchConfig,
34+
migrateLegacyWebFetchConfig,
35+
migrateLegacyXSearchConfig,
36+
]) {
37+
const migrated = migrate(next);
38+
if (migrated.changes.length === 0) {
39+
continue;
40+
}
41+
next = migrated.config;
42+
changes.push(...migrated.changes);
43+
}
44+
45+
next = normalizeLegacyNanoBananaSkill(next, changes);
46+
next = normalizeLegacyTalkConfig(next, changes);
47+
next = normalizeLegacyCrossContextMessageConfig(next, changes);
48+
next = normalizeLegacyMediaProviderOptions(next, changes);
49+
next = normalizeLegacyMistralModelMaxTokens(next, changes);
50+
51+
return { config: next, changes };
52+
}

src/commands/doctor/shared/legacy-config-migrations.runtime.ts

Lines changed: 2 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from "../../../config/legacy.shared.js";
1515
import { DEFAULT_GATEWAY_PORT } from "../../../config/paths.js";
1616
import { isBlockedObjectKey } from "../../../config/prototype-keys.js";
17+
import { LEGACY_CONFIG_MIGRATIONS_RUNTIME_TTS } from "./legacy-config-migrations.runtime.tts.js";
1718
import { migrateLegacyXSearchConfig } from "./legacy-x-search-migrate.js";
1819

1920
const AGENT_HEARTBEAT_KEYS = new Set([
@@ -34,9 +35,6 @@ const AGENT_HEARTBEAT_KEYS = new Set([
3435
]);
3536

3637
const CHANNEL_HEARTBEAT_KEYS = new Set(["showOk", "showAlerts", "useIndicator"]);
37-
const LEGACY_TTS_PROVIDER_KEYS = ["openai", "elevenlabs", "microsoft", "edge"] as const;
38-
const LEGACY_TTS_PLUGIN_IDS = new Set(["voice-call"]);
39-
4038
function sandboxScopeFromPerSession(perSession: boolean): "session" | "shared" {
4139
return perSession ? "session" : "shared";
4240
}
@@ -131,14 +129,6 @@ function mergeLegacyIntoDefaults(params: {
131129
params.raw[params.rootKey] = root;
132130
}
133131

134-
function hasLegacyTtsProviderKeys(value: unknown): boolean {
135-
const tts = getRecord(value);
136-
if (!tts) {
137-
return false;
138-
}
139-
return LEGACY_TTS_PROVIDER_KEYS.some((key) => Object.prototype.hasOwnProperty.call(tts, key));
140-
}
141-
142132
function hasLegacySandboxPerSession(value: unknown): boolean {
143133
const sandbox = getRecord(value);
144134
return Boolean(sandbox && Object.prototype.hasOwnProperty.call(sandbox, "perSession"));
@@ -150,72 +140,6 @@ function hasLegacyAgentListSandboxPerSession(value: unknown): boolean {
150140
}
151141
return value.some((agent) => hasLegacySandboxPerSession(getRecord(agent)?.sandbox));
152142
}
153-
function hasLegacyPluginEntryTtsProviderKeys(value: unknown): boolean {
154-
const entries = getRecord(value);
155-
if (!entries) {
156-
return false;
157-
}
158-
return Object.entries(entries).some(([pluginId, entryValue]) => {
159-
if (isBlockedObjectKey(pluginId) || !LEGACY_TTS_PLUGIN_IDS.has(pluginId)) {
160-
return false;
161-
}
162-
const entry = getRecord(entryValue);
163-
const config = getRecord(entry?.config);
164-
return hasLegacyTtsProviderKeys(config?.tts);
165-
});
166-
}
167-
168-
function getOrCreateTtsProviders(tts: Record<string, unknown>): Record<string, unknown> {
169-
const providers = getRecord(tts.providers) ?? {};
170-
tts.providers = providers;
171-
return providers;
172-
}
173-
174-
function mergeLegacyTtsProviderConfig(
175-
tts: Record<string, unknown>,
176-
legacyKey: string,
177-
providerId: string,
178-
): boolean {
179-
const legacyValue = getRecord(tts[legacyKey]);
180-
if (!legacyValue) {
181-
return false;
182-
}
183-
const providers = getOrCreateTtsProviders(tts);
184-
const existing = getRecord(providers[providerId]) ?? {};
185-
const merged = structuredClone(existing);
186-
mergeMissing(merged, legacyValue);
187-
providers[providerId] = merged;
188-
delete tts[legacyKey];
189-
return true;
190-
}
191-
192-
function migrateLegacyTtsConfig(
193-
tts: Record<string, unknown> | null | undefined,
194-
pathLabel: string,
195-
changes: string[],
196-
): void {
197-
if (!tts) {
198-
return;
199-
}
200-
const movedOpenAI = mergeLegacyTtsProviderConfig(tts, "openai", "openai");
201-
const movedElevenLabs = mergeLegacyTtsProviderConfig(tts, "elevenlabs", "elevenlabs");
202-
const movedMicrosoft = mergeLegacyTtsProviderConfig(tts, "microsoft", "microsoft");
203-
const movedEdge = mergeLegacyTtsProviderConfig(tts, "edge", "microsoft");
204-
205-
if (movedOpenAI) {
206-
changes.push(`Moved ${pathLabel}.openai → ${pathLabel}.providers.openai.`);
207-
}
208-
if (movedElevenLabs) {
209-
changes.push(`Moved ${pathLabel}.elevenlabs → ${pathLabel}.providers.elevenlabs.`);
210-
}
211-
if (movedMicrosoft) {
212-
changes.push(`Moved ${pathLabel}.microsoft → ${pathLabel}.providers.microsoft.`);
213-
}
214-
if (movedEdge) {
215-
changes.push(`Moved ${pathLabel}.edge → ${pathLabel}.providers.microsoft.`);
216-
}
217-
}
218-
219143
const MEMORY_SEARCH_RULE: LegacyConfigRule = {
220144
path: ["memorySearch"],
221145
message:
@@ -242,21 +166,6 @@ const X_SEARCH_RULE: LegacyConfigRule = {
242166
'tools.web.x_search.apiKey moved to the xAI plugin; use plugins.entries.xai.config.webSearch.apiKey instead. Run "openclaw doctor --fix".',
243167
};
244168

245-
const LEGACY_TTS_RULES: LegacyConfigRule[] = [
246-
{
247-
path: ["messages", "tts"],
248-
message:
249-
'messages.tts.<provider> keys (openai/elevenlabs/microsoft/edge) are legacy; use messages.tts.providers.<provider>. Run "openclaw doctor --fix".',
250-
match: (value) => hasLegacyTtsProviderKeys(value),
251-
},
252-
{
253-
path: ["plugins", "entries"],
254-
message:
255-
'plugins.entries.voice-call.config.tts.<provider> keys (openai/elevenlabs/microsoft/edge) are legacy; use plugins.entries.voice-call.config.tts.providers.<provider>. Run "openclaw doctor --fix".',
256-
match: (value) => hasLegacyPluginEntryTtsProviderKeys(value),
257-
},
258-
];
259-
260169
const LEGACY_SANDBOX_SCOPE_RULES: LegacyConfigRule[] = [
261170
{
262171
path: ["agents", "defaults", "sandbox"],
@@ -447,33 +356,7 @@ export const LEGACY_CONFIG_MIGRATIONS_RUNTIME: LegacyConfigMigrationSpec[] = [
447356
changes.push(`Normalized gateway.bind "${escapeControlForLog(bindRaw)}" → "${mapped}".`);
448357
},
449358
}),
450-
defineLegacyConfigMigration({
451-
id: "tts.providers-generic-shape",
452-
describe: "Move legacy bundled TTS config keys into messages.tts.providers",
453-
legacyRules: LEGACY_TTS_RULES,
454-
apply: (raw, changes) => {
455-
const messages = getRecord(raw.messages);
456-
migrateLegacyTtsConfig(getRecord(messages?.tts), "messages.tts", changes);
457-
458-
const plugins = getRecord(raw.plugins);
459-
const pluginEntries = getRecord(plugins?.entries);
460-
if (!pluginEntries) {
461-
return;
462-
}
463-
for (const [pluginId, entryValue] of Object.entries(pluginEntries)) {
464-
if (isBlockedObjectKey(pluginId) || !LEGACY_TTS_PLUGIN_IDS.has(pluginId)) {
465-
continue;
466-
}
467-
const entry = getRecord(entryValue);
468-
const config = getRecord(entry?.config);
469-
migrateLegacyTtsConfig(
470-
getRecord(config?.tts),
471-
`plugins.entries.${pluginId}.config.tts`,
472-
changes,
473-
);
474-
}
475-
},
476-
}),
359+
...LEGACY_CONFIG_MIGRATIONS_RUNTIME_TTS,
477360
defineLegacyConfigMigration({
478361
id: "heartbeat->agents.defaults.heartbeat",
479362
describe: "Move top-level heartbeat to agents.defaults.heartbeat/channels.defaults.heartbeat",

0 commit comments

Comments
 (0)