Skip to content

Commit 771881d

Browse files
vortexopenclawAriel Bravyvincentkoc
authored
fix(elevenlabs): use current TTS model ids (#92904)
* fix(elevenlabs): use current TTS model ids * fix(elevenlabs): preserve served legacy model choices --------- Co-authored-by: Ariel Bravy <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
1 parent 6db496b commit 771881d

2 files changed

Lines changed: 76 additions & 8 deletions

File tree

extensions/elevenlabs/speech-provider.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,60 @@ describe("elevenlabs speech provider", () => {
4646
expect(provider.models).toEqual([
4747
"eleven_v3",
4848
"eleven_multilingual_v2",
49+
"eleven_flash_v2_5",
50+
"eleven_flash_v2",
4951
"eleven_turbo_v2_5",
5052
"eleven_monolingual_v1",
5153
]);
5254
});
5355

56+
it("keeps non-equivalent deprecated ElevenLabs TTS model IDs", async () => {
57+
const provider = buildElevenLabsSpeechProvider();
58+
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
59+
const body = parseRequestBody(init);
60+
expect(body.model_id).toBe("eleven_monolingual_v1");
61+
return new Response(new Uint8Array([1, 2, 3]), { status: 200 });
62+
});
63+
globalThis.fetch = fetchMock as unknown as typeof fetch;
64+
65+
await provider.synthesizeTelephony?.({
66+
text: "hello",
67+
cfg: {} as never,
68+
providerConfig: {
69+
apiKey: "xi-test",
70+
modelId: "eleven_monolingual_v1",
71+
},
72+
timeoutMs: 1_000,
73+
});
74+
75+
expect(fetchMock).toHaveBeenCalledTimes(1);
76+
});
77+
78+
it("maps deprecated ElevenLabs TTS model IDs in overrides", async () => {
79+
const provider = buildElevenLabsSpeechProvider();
80+
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
81+
const body = parseRequestBody(init);
82+
expect(body.model_id).toBe("eleven_flash_v2_5");
83+
return new Response(new Uint8Array([1, 2, 3]), { status: 200 });
84+
});
85+
globalThis.fetch = fetchMock as unknown as typeof fetch;
86+
87+
await provider.synthesizeTelephony?.({
88+
text: "hello",
89+
cfg: {} as never,
90+
providerConfig: {
91+
apiKey: "xi-test",
92+
modelId: "eleven_multilingual_v2",
93+
},
94+
providerOverrides: {
95+
modelId: "eleven_turbo_v2_5",
96+
},
97+
timeoutMs: 1_000,
98+
});
99+
100+
expect(fetchMock).toHaveBeenCalledTimes(1);
101+
});
102+
54103
it("validates ElevenLabs voice ID length and character rules", () => {
55104
const cases = [
56105
{ value: "pMsXgVXv3BLzUgSXRplE", expected: true },

extensions/elevenlabs/speech-provider.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,23 @@ const DEFAULT_ELEVENLABS_VOICE_SETTINGS = {
4141
const ELEVENLABS_TTS_MODELS = [
4242
"eleven_v3",
4343
"eleven_multilingual_v2",
44+
"eleven_flash_v2_5",
45+
"eleven_flash_v2",
4446
"eleven_turbo_v2_5",
4547
"eleven_monolingual_v1",
4648
] as const;
4749

50+
function normalizeElevenLabsTtsModelId(value: string | undefined): string | undefined {
51+
switch (value) {
52+
case "eleven_turbo_v2_5":
53+
return "eleven_flash_v2_5";
54+
case "eleven_turbo_v2":
55+
return "eleven_flash_v2";
56+
default:
57+
return value;
58+
}
59+
}
60+
4861
type ElevenLabsProviderConfig = {
4962
apiKey?: string;
5063
baseUrl: string;
@@ -136,7 +149,8 @@ function normalizeElevenLabsProviderConfig(
136149
}),
137150
baseUrl: normalizeElevenLabsBaseUrl(trimToUndefined(raw?.baseUrl)),
138151
voiceId: trimToUndefined(raw?.voiceId) ?? DEFAULT_ELEVENLABS_VOICE_ID,
139-
modelId: trimToUndefined(raw?.modelId) ?? DEFAULT_ELEVENLABS_MODEL_ID,
152+
modelId:
153+
normalizeElevenLabsTtsModelId(trimToUndefined(raw?.modelId)) ?? DEFAULT_ELEVENLABS_MODEL_ID,
140154
seed: normalizeElevenLabsSeed(raw?.seed),
141155
applyTextNormalization: trimToUndefined(raw?.applyTextNormalization) as
142156
| "auto"
@@ -158,7 +172,7 @@ function readElevenLabsProviderConfig(config: SpeechProviderConfig): ElevenLabsP
158172
apiKey: trimToUndefined(config.apiKey) ?? defaults.apiKey,
159173
baseUrl: normalizeElevenLabsBaseUrl(trimToUndefined(config.baseUrl) ?? defaults.baseUrl),
160174
voiceId: trimToUndefined(config.voiceId) ?? defaults.voiceId,
161-
modelId: trimToUndefined(config.modelId) ?? defaults.modelId,
175+
modelId: normalizeElevenLabsTtsModelId(trimToUndefined(config.modelId)) ?? defaults.modelId,
162176
seed: normalizeElevenLabsSeed(config.seed) ?? defaults.seed,
163177
applyTextNormalization:
164178
(trimToUndefined(config.applyTextNormalization) as "auto" | "on" | "off" | undefined) ??
@@ -222,7 +236,7 @@ function parseDirectiveToken(ctx: SpeechDirectiveTokenParseContext) {
222236
}
223237
return {
224238
handled: true,
225-
overrides: { ...ctx.currentOverrides, modelId: ctx.value },
239+
overrides: { ...ctx.currentOverrides, modelId: normalizeElevenLabsTtsModelId(ctx.value) },
226240
};
227241
case "stability": {
228242
if (!ctx.policy.allowVoiceSettings) {
@@ -407,7 +421,9 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
407421
: { voiceId: trimToUndefined(talkProviderConfig.voiceId) }),
408422
...(trimToUndefined(talkProviderConfig.modelId) == null
409423
? {}
410-
: { modelId: trimToUndefined(talkProviderConfig.modelId) }),
424+
: {
425+
modelId: normalizeElevenLabsTtsModelId(trimToUndefined(talkProviderConfig.modelId)),
426+
}),
411427
...(normalizeElevenLabsSeed(talkProviderConfig.seed) == null
412428
? {}
413429
: { seed: normalizeElevenLabsSeed(talkProviderConfig.seed) }),
@@ -456,7 +472,7 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
456472
: { voiceId: trimToUndefined(params.voiceId) }),
457473
...(trimToUndefined(params.modelId) == null
458474
? {}
459-
: { modelId: trimToUndefined(params.modelId) }),
475+
: { modelId: normalizeElevenLabsTtsModelId(trimToUndefined(params.modelId)) }),
460476
...(trimToUndefined(params.outputFormat) == null
461477
? {}
462478
: { outputFormat: trimToUndefined(params.outputFormat) }),
@@ -511,7 +527,8 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
511527
apiKey,
512528
baseUrl: config.baseUrl,
513529
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
514-
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
530+
modelId:
531+
normalizeElevenLabsTtsModelId(trimToUndefined(overrides.modelId)) ?? config.modelId,
515532
outputFormat,
516533
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
517534
applyTextNormalization:
@@ -549,7 +566,8 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
549566
apiKey,
550567
baseUrl: config.baseUrl,
551568
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
552-
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
569+
modelId:
570+
normalizeElevenLabsTtsModelId(trimToUndefined(overrides.modelId)) ?? config.modelId,
553571
outputFormat,
554572
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
555573
applyTextNormalization:
@@ -586,7 +604,8 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
586604
apiKey,
587605
baseUrl: config.baseUrl,
588606
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
589-
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
607+
modelId:
608+
normalizeElevenLabsTtsModelId(trimToUndefined(overrides.modelId)) ?? config.modelId,
590609
outputFormat,
591610
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
592611
applyTextNormalization:

0 commit comments

Comments
 (0)