Skip to content

Commit c0a4a78

Browse files
fix(doctor): keep TTS legacy migration on supported paths (#91787)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
1 parent 0a6a101 commit c0a4a78

4 files changed

Lines changed: 184 additions & 34 deletions

File tree

extensions/discord/src/doctor.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,88 @@ describe("discord doctor", () => {
119119
expect(mainTts?.edge).toBeUndefined();
120120
});
121121

122+
it("does not move unsupported root and account tts provider aliases", () => {
123+
const normalize = getDiscordCompatibilityNormalizer();
124+
125+
const result = normalize({
126+
cfg: {
127+
channels: {
128+
discord: {
129+
tts: {
130+
edge: {
131+
voice: "en-US-RootNeural",
132+
},
133+
},
134+
voice: {
135+
tts: {
136+
edge: {
137+
voice: "en-US-VoiceNeural",
138+
},
139+
},
140+
},
141+
accounts: {
142+
main: {
143+
tts: {
144+
edge: {
145+
voice: "en-US-AccountNeural",
146+
},
147+
},
148+
voice: {
149+
tts: {
150+
edge: {
151+
voice: "en-US-AccountVoiceNeural",
152+
},
153+
},
154+
},
155+
},
156+
},
157+
},
158+
},
159+
} as never,
160+
});
161+
162+
expect(result.changes).toEqual([
163+
"Moved channels.discord.accounts.main.voice.tts.edge → channels.discord.accounts.main.voice.tts.providers.microsoft.",
164+
"Moved channels.discord.voice.tts.edge → channels.discord.voice.tts.providers.microsoft.",
165+
]);
166+
const discordConfig = result.config.channels?.discord as
167+
| {
168+
tts?: Record<string, unknown>;
169+
voice?: { tts?: Record<string, unknown> };
170+
accounts?: {
171+
main?: {
172+
tts?: Record<string, unknown>;
173+
voice?: { tts?: Record<string, unknown> };
174+
};
175+
};
176+
}
177+
| undefined;
178+
expect(discordConfig?.tts).toEqual({
179+
edge: {
180+
voice: "en-US-RootNeural",
181+
},
182+
});
183+
expect(discordConfig?.accounts?.main?.tts).toEqual({
184+
edge: {
185+
voice: "en-US-AccountNeural",
186+
},
187+
});
188+
expect(discordConfig?.voice?.tts).toEqual({
189+
providers: {
190+
microsoft: {
191+
voice: "en-US-VoiceNeural",
192+
},
193+
},
194+
});
195+
expect(discordConfig?.accounts?.main?.voice?.tts).toEqual({
196+
providers: {
197+
microsoft: {
198+
voice: "en-US-AccountVoiceNeural",
199+
},
200+
},
201+
});
202+
});
203+
122204
it("removes unsupported Discord realtime wake names", () => {
123205
const normalize = getDiscordCompatibilityNormalizer();
124206

src/commands/doctor/shared/deprecation-compat.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,10 @@ const DOCTOR_DEPRECATION_COMPAT_RECORDS = [
231231
owner: "tts",
232232
introduced: "2026-04-29",
233233
source:
234-
"messages.tts.enabled, agents.*.tts.enabled, channels.*.tts.enabled, and voice-call plugin tts.enabled",
234+
"messages.tts.enabled, agents.list[].tts.enabled, supported channel TTS enabled fields, and voice-call plugin tts.enabled",
235235
migration: "src/commands/doctor/shared/legacy-config-migrations.runtime.tts.ts",
236236
replacement:
237-
'messages/agents/channels/plugins TTS auto mode, for example auto: "always" or auto: "off"',
237+
'supported messages/agents/channels/plugins TTS auto mode, for example auto: "always" or auto: "off"',
238238
docsPath: "/tools/tts",
239239
tests: ["src/commands/doctor/shared/legacy-config-migrate.provider-shapes.test.ts"],
240240
}),

src/commands/doctor/shared/legacy-config-migrate.provider-shapes.test.ts

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,18 @@ describe("legacy migrate provider-shaped config", () => {
233233
},
234234
},
235235
},
236+
list: [
237+
{
238+
id: "voice-agent",
239+
tts: {
240+
providers: {
241+
openai: {
242+
voice: "cedar",
243+
},
244+
},
245+
},
246+
},
247+
],
236248
},
237249
channels: {
238250
discord: {
@@ -297,10 +309,8 @@ describe("legacy migrate provider-shaped config", () => {
297309
"Moved messages.tts.providers.elevenlabs.voiceId → messages.tts.providers.elevenlabs.speakerVoiceId.",
298310
"Moved messages.tts.providers.openai.voice → messages.tts.providers.openai.speakerVoice.",
299311
"Moved messages.tts.personas.narrator.providers.google.voiceName → messages.tts.personas.narrator.providers.google.speakerVoice.",
300-
"Removed agents.defaults.tts.providers.openai.voice because agents.defaults.tts.providers.openai.speakerVoice is already set.",
301-
"Moved channels.discord.tts.providers.microsoft.voice → channels.discord.tts.providers.microsoft.speakerVoice.",
312+
"Moved agents.list[0].tts.providers.openai.voice → agents.list[0].tts.providers.openai.speakerVoice.",
302313
"Moved channels.discord.voice.tts.providers.openai.voice → channels.discord.voice.tts.providers.openai.speakerVoice.",
303-
"Removed channels.discord.accounts.primary.tts.providers.gradium.voiceId because channels.discord.accounts.primary.tts.providers.gradium.speakerVoiceId is already set.",
304314
"Moved channels.discord.accounts.primary.voice.tts.providers.openai.voiceId → channels.discord.accounts.primary.voice.tts.providers.openai.speakerVoiceId.",
305315
"Moved plugins.entries.voice-call.config.tts.providers.xai.voiceId → plugins.entries.voice-call.config.tts.providers.xai.speakerVoiceId.",
306316
]);
@@ -326,7 +336,10 @@ describe("legacy migrate provider-shaped config", () => {
326336
});
327337
const migratedConfig = res.config as
328338
| {
329-
agents?: { defaults?: { tts?: Record<string, unknown> } };
339+
agents?: {
340+
defaults?: { tts?: Record<string, unknown> };
341+
list?: Array<{ id?: string; tts?: Record<string, unknown> }>;
342+
};
330343
channels?: {
331344
discord?: {
332345
tts?: Record<string, unknown>;
@@ -347,14 +360,25 @@ describe("legacy migrate provider-shaped config", () => {
347360
expect(migratedConfig?.agents?.defaults?.tts).toEqual({
348361
providers: {
349362
openai: {
363+
voice: "cedar",
350364
speakerVoice: "marin",
351365
},
352366
},
353367
});
368+
expect(migratedConfig?.agents?.list?.[0]).toEqual({
369+
id: "voice-agent",
370+
tts: {
371+
providers: {
372+
openai: {
373+
speakerVoice: "cedar",
374+
},
375+
},
376+
},
377+
});
354378
expect(migratedConfig?.channels?.discord?.tts).toEqual({
355379
providers: {
356380
microsoft: {
357-
speakerVoice: "en-US-AvaNeural",
381+
voice: "en-US-AvaNeural",
358382
},
359383
},
360384
});
@@ -368,6 +392,7 @@ describe("legacy migrate provider-shaped config", () => {
368392
expect(migratedConfig?.channels?.discord?.accounts?.primary?.tts).toEqual({
369393
providers: {
370394
gradium: {
395+
voiceId: "voice-2",
371396
speakerVoiceId: "voice-current",
372397
},
373398
},
@@ -416,11 +441,33 @@ describe("legacy migrate provider-shaped config", () => {
416441
tts: {
417442
enabled: true,
418443
},
444+
voice: {
445+
tts: {
446+
enabled: false,
447+
},
448+
},
419449
accounts: {
420450
primary: {
421451
tts: {
422452
enabled: false,
423453
},
454+
voice: {
455+
tts: {
456+
enabled: true,
457+
},
458+
},
459+
},
460+
},
461+
},
462+
feishu: {
463+
tts: {
464+
enabled: true,
465+
},
466+
accounts: {
467+
english: {
468+
tts: {
469+
enabled: false,
470+
},
424471
},
425472
},
426473
},
@@ -440,23 +487,34 @@ describe("legacy migrate provider-shaped config", () => {
440487

441488
expect(res.changes).toEqual([
442489
'Moved messages.tts.enabled → messages.tts.auto "always".',
443-
'Moved agents.defaults.tts.enabled → agents.defaults.tts.auto "off".',
444490
"Removed agents.list[0].tts.enabled because agents.list[0].tts.auto is already set.",
445-
'Moved channels.discord.tts.enabled → channels.discord.tts.auto "always".',
446-
'Moved channels.discord.accounts.primary.tts.enabled → channels.discord.accounts.primary.tts.auto "off".',
491+
'Moved channels.discord.voice.tts.enabled → channels.discord.voice.tts.auto "off".',
492+
'Moved channels.discord.accounts.primary.voice.tts.enabled → channels.discord.accounts.primary.voice.tts.auto "always".',
493+
'Moved channels.feishu.tts.enabled → channels.feishu.tts.auto "always".',
494+
'Moved channels.feishu.accounts.english.tts.enabled → channels.feishu.accounts.english.tts.auto "off".',
447495
'Moved plugins.entries.voice-call.config.tts.enabled → plugins.entries.voice-call.config.tts.auto "always".',
448496
]);
449497
const migratedConfig = res.config as
450498
| {
451499
messages?: { tts?: { auto?: unknown } };
452500
agents?: {
453-
defaults?: { tts?: { auto?: unknown } };
501+
defaults?: { tts?: { enabled?: unknown; auto?: unknown } };
454502
list?: Array<{ id?: string; tts?: { auto?: unknown } }>;
455503
};
456504
channels?: {
457505
discord?: {
506+
tts?: { enabled?: unknown; auto?: unknown };
507+
voice?: { tts?: { auto?: unknown } };
508+
accounts?: {
509+
primary?: {
510+
tts?: { enabled?: unknown; auto?: unknown };
511+
voice?: { tts?: { auto?: unknown } };
512+
};
513+
};
514+
};
515+
feishu?: {
458516
tts?: { auto?: unknown };
459-
accounts?: { primary?: { tts?: { auto?: unknown } } };
517+
accounts?: { english?: { tts?: { auto?: unknown } } };
460518
};
461519
};
462520
plugins?: {
@@ -465,13 +523,19 @@ describe("legacy migrate provider-shaped config", () => {
465523
}
466524
| undefined;
467525
expect(migratedConfig?.messages?.tts?.auto).toBe("always");
468-
expect(migratedConfig?.agents?.defaults?.tts?.auto).toBe("off");
526+
expect(migratedConfig?.agents?.defaults?.tts).toEqual({ enabled: false });
469527
expect(migratedConfig?.agents?.list?.[0]).toEqual({
470528
id: "voice-agent",
471529
tts: { auto: "tagged" },
472530
});
473-
expect(migratedConfig?.channels?.discord?.tts?.auto).toBe("always");
474-
expect(migratedConfig?.channels?.discord?.accounts?.primary?.tts?.auto).toBe("off");
531+
expect(migratedConfig?.channels?.discord?.tts).toEqual({ enabled: true });
532+
expect(migratedConfig?.channels?.discord?.voice?.tts?.auto).toBe("off");
533+
expect(migratedConfig?.channels?.discord?.accounts?.primary?.tts).toEqual({
534+
enabled: false,
535+
});
536+
expect(migratedConfig?.channels?.discord?.accounts?.primary?.voice?.tts?.auto).toBe("always");
537+
expect(migratedConfig?.channels?.feishu?.tts?.auto).toBe("always");
538+
expect(migratedConfig?.channels?.feishu?.accounts?.english?.tts?.auto).toBe("off");
475539
expect(migratedConfig?.plugins?.entries?.["voice-call"]?.config?.tts?.auto).toBe("always");
476540
});
477541

0 commit comments

Comments
 (0)