fix: validate elevenlabs speech seeds

This commit is contained in:
Peter Steinberger
2026-05-28 17:01:56 -04:00
parent 516be11db9
commit b5202f975b
2 changed files with 42 additions and 8 deletions

View File

@@ -159,4 +159,29 @@ describe("elevenlabs speech provider", () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
});
it("drops malformed seed values before synthesis", async () => {
const provider = buildElevenLabsSpeechProvider();
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
const body = parseRequestBody(init);
expect(body).not.toHaveProperty("seed");
return new Response(new Uint8Array([1, 2, 3]), { status: 200 });
});
globalThis.fetch = fetchMock as unknown as typeof fetch;
await provider.synthesizeTelephony?.({
text: "hello",
cfg: {} as never,
providerConfig: {
apiKey: "xi-test",
seed: 1.5,
},
providerOverrides: {
seed: Number.POSITIVE_INFINITY,
},
timeoutMs: 1_000,
});
expect(fetchMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -83,6 +83,13 @@ function normalizeVoiceSetting(value: unknown, min: number, max: number): number
return number !== undefined && number >= min && number <= max ? number : undefined;
}
function normalizeElevenLabsSeed(value: unknown): number | undefined {
const seed = asFiniteNumber(value);
return seed !== undefined && Number.isSafeInteger(seed) && seed >= 0 && seed <= 4_294_967_295
? seed
: undefined;
}
function normalizeVoiceSettings(
rawVoiceSettings: Record<string, unknown> | undefined,
): Partial<ElevenLabsProviderConfig["voiceSettings"]> {
@@ -119,7 +126,7 @@ function normalizeElevenLabsProviderConfig(
baseUrl: normalizeElevenLabsBaseUrl(trimToUndefined(raw?.baseUrl)),
voiceId: trimToUndefined(raw?.voiceId) ?? DEFAULT_ELEVENLABS_VOICE_ID,
modelId: trimToUndefined(raw?.modelId) ?? DEFAULT_ELEVENLABS_MODEL_ID,
seed: asFiniteNumber(raw?.seed),
seed: normalizeElevenLabsSeed(raw?.seed),
applyTextNormalization: trimToUndefined(raw?.applyTextNormalization) as
| "auto"
| "on"
@@ -141,7 +148,7 @@ function readElevenLabsProviderConfig(config: SpeechProviderConfig): ElevenLabsP
baseUrl: normalizeElevenLabsBaseUrl(trimToUndefined(config.baseUrl) ?? defaults.baseUrl),
voiceId: trimToUndefined(config.voiceId) ?? defaults.voiceId,
modelId: trimToUndefined(config.modelId) ?? defaults.modelId,
seed: asFiniteNumber(config.seed) ?? defaults.seed,
seed: normalizeElevenLabsSeed(config.seed) ?? defaults.seed,
applyTextNormalization:
(trimToUndefined(config.applyTextNormalization) as "auto" | "on" | "off" | undefined) ??
defaults.applyTextNormalization,
@@ -389,9 +396,9 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
...(trimToUndefined(talkProviderConfig.modelId) == null
? {}
: { modelId: trimToUndefined(talkProviderConfig.modelId) }),
...(asFiniteNumber(talkProviderConfig.seed) == null
...(normalizeElevenLabsSeed(talkProviderConfig.seed) == null
? {}
: { seed: asFiniteNumber(talkProviderConfig.seed) }),
: { seed: normalizeElevenLabsSeed(talkProviderConfig.seed) }),
...(trimToUndefined(talkProviderConfig.applyTextNormalization) == null
? {}
: {
@@ -441,7 +448,9 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
...(trimToUndefined(params.outputFormat) == null
? {}
: { outputFormat: trimToUndefined(params.outputFormat) }),
...(asFiniteNumber(params.seed) == null ? {} : { seed: asFiniteNumber(params.seed) }),
...(normalizeElevenLabsSeed(params.seed) == null
? {}
: { seed: normalizeElevenLabsSeed(params.seed) }),
...(normalize == null
? {}
: { applyTextNormalization: normalizeApplyTextNormalization(normalize) }),
@@ -492,7 +501,7 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
outputFormat,
seed: asFiniteNumber(overrides.seed) ?? config.seed,
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
applyTextNormalization:
(trimToUndefined(overrides.applyTextNormalization) as
| "auto"
@@ -530,7 +539,7 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
outputFormat,
seed: asFiniteNumber(overrides.seed) ?? config.seed,
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
applyTextNormalization:
(trimToUndefined(overrides.applyTextNormalization) as
| "auto"
@@ -567,7 +576,7 @@ export function buildElevenLabsSpeechProvider(): SpeechProviderPlugin {
voiceId: trimToUndefined(overrides.voiceId) ?? config.voiceId,
modelId: trimToUndefined(overrides.modelId) ?? config.modelId,
outputFormat,
seed: asFiniteNumber(overrides.seed) ?? config.seed,
seed: normalizeElevenLabsSeed(overrides.seed) ?? config.seed,
applyTextNormalization:
(trimToUndefined(overrides.applyTextNormalization) as
| "auto"