fix(elevenlabs): use guarded TTS fetch

This commit is contained in:
Peter Steinberger
2026-04-24 19:44:40 +01:00
parent 8d57d745cf
commit d12b523611
2 changed files with 20 additions and 14 deletions

View File

@@ -47,6 +47,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Models/configure: preserve the existing default model when provider auth is re-run from configure while keeping explicit default-setting commands authoritative. Fixes #70696. (#70793) Thanks @Sathvik-1007.
- Codex harness/models: keep legacy `codex/*` harness shorthand out of model picker and `/models` choice surfaces while migrating primary legacy refs to canonical `openai/*` plus explicit Codex harness config. (#71193) Thanks @vincentkoc.
- Plugins/runtime deps: respect explicit plugin and channel disablement when repairing bundled runtime dependencies, so doctor and health checks no longer install deps for disabled configured channels.
- Diagnostics: harden tool and model diagnostic events against hostile errors, blocking listeners, and unsafe stability reason fields. Thanks @vincentkoc.

View File

@@ -5,6 +5,10 @@ import {
normalizeSeed,
requireInRange,
} from "openclaw/plugin-sdk/speech";
import {
fetchWithSsrFGuard,
ssrfPolicyFromHttpBaseUrlAllowedHostname,
} from "openclaw/plugin-sdk/ssrf-runtime";
import { isValidElevenLabsVoiceId, normalizeElevenLabsBaseUrl } from "./shared.js";
function assertElevenLabsVoiceSettings(settings: {
@@ -61,17 +65,15 @@ export async function elevenLabsTTS(params: {
const normalizedLanguage = normalizeLanguageCode(languageCode);
const normalizedNormalization = normalizeApplyTextNormalization(applyTextNormalization);
const normalizedSeed = normalizeSeed(seed);
const normalizedBaseUrl = normalizeElevenLabsBaseUrl(baseUrl);
const url = new URL(`${normalizedBaseUrl}/v1/text-to-speech/${voiceId}`);
if (outputFormat) {
url.searchParams.set("output_format", outputFormat);
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const url = new URL(`${normalizeElevenLabsBaseUrl(baseUrl)}/v1/text-to-speech/${voiceId}`);
if (outputFormat) {
url.searchParams.set("output_format", outputFormat);
}
const response = await fetch(url.toString(), {
const { response, release } = await fetchWithSsrFGuard({
url: url.toString(),
init: {
method: "POST",
headers: {
"xi-api-key": apiKey,
@@ -93,13 +95,16 @@ export async function elevenLabsTTS(params: {
speed: voiceSettings.speed,
},
}),
signal: controller.signal,
});
},
timeoutMs,
policy: ssrfPolicyFromHttpBaseUrlAllowedHostname(normalizedBaseUrl),
auditContext: "elevenlabs.tts",
});
try {
await assertOkOrThrowProviderError(response, "ElevenLabs API error");
return Buffer.from(await response.arrayBuffer());
} finally {
clearTimeout(timeout);
await release();
}
}