openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
150 lines (149 loc) • 6.21 kB
JavaScript
import { t as XAI_BASE_URL } from "./model-definitions-BejEvn8r.mjs";
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
import { asFiniteNumberInRange, asOptionalObjectRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
//#region extensions/xai/speech-provider-metadata-factory.ts
const XAI_SPEECH_RESPONSE_FORMATS = [
"mp3",
"wav",
"pcm",
"mulaw",
"alaw"
];
const XAI_TTS_FALLBACK_VOICES = [
"ara",
"eve",
"leo",
"rex",
"sal"
];
function normalizeXaiTtsBaseUrl(baseUrl) {
return normalizeOptionalString(baseUrl)?.replace(/\/+$/, "") ?? XAI_BASE_URL;
}
function isValidXaiTtsVoice(voice) {
return normalizeOptionalString(voice) !== void 0;
}
function normalizeXaiLanguageCode(value) {
const normalized = normalizeOptionalString(value)?.toLowerCase();
if (!normalized) return;
if (normalized === "auto" || /^[a-z]{2,3}(?:-[a-z]{2,4})?$/.test(normalized)) return normalized;
throw new Error(`xAI language must be "auto" or a BCP-47 tag (e.g. "en", "pt-br", "zh-cn"); got: ${normalized}`);
}
function normalizeXaiSpeechSpeed(value) {
return asFiniteNumberInRange(value, {
min: .7,
max: 1.5
});
}
function normalizeXaiSpeechResponseFormat(value) {
const next = normalizeLowercaseStringOrEmpty(value);
if (!next) return;
const format = XAI_SPEECH_RESPONSE_FORMATS.find((candidate) => candidate === next);
if (format) return format;
throw new Error(`Invalid xAI speech responseFormat: ${next}`);
}
function resolveXaiSpeechResponseFormat(target, configuredFormat) {
return target === "voice-note" ? "mp3" : configuredFormat ?? "mp3";
}
function xaiSpeechResponseFormatToFileExtension(format) {
return format === "wav" || format === "pcm" || format === "mulaw" || format === "alaw" ? `.${format}` : ".mp3";
}
function normalizeXaiSpeechProviderConfig(rawConfig) {
const providers = asOptionalObjectRecord(rawConfig.providers);
const xai = asOptionalObjectRecord(providers?.xai ?? rawConfig.xai ?? rawConfig) ?? {};
return {
apiKey: normalizeResolvedSecretInputString({
value: xai.apiKey,
path: "tts.providers.xai.apiKey"
}),
baseUrl: normalizeXaiTtsBaseUrl(normalizeOptionalString(xai.baseUrl) ?? normalizeOptionalString(process.env.XAI_BASE_URL) ?? XAI_BASE_URL),
voiceId: normalizeOptionalString(xai.voiceId ?? xai.voice) ?? "eve",
language: normalizeXaiLanguageCode(xai.language ?? xai.languageCode),
speed: normalizeXaiSpeechSpeed(xai.speed),
responseFormat: normalizeXaiSpeechResponseFormat(xai.responseFormat)
};
}
function readXaiSpeechProviderConfig(config) {
const normalized = normalizeXaiSpeechProviderConfig({});
return {
apiKey: normalizeOptionalString(config.apiKey),
baseUrl: normalizeOptionalString(config.baseUrl) ?? normalized.baseUrl,
voiceId: normalizeOptionalString(config.voiceId ?? config.voice) ?? normalized.voiceId,
language: normalizeXaiLanguageCode(config.language ?? config.languageCode),
speed: normalizeXaiSpeechSpeed(config.speed),
responseFormat: normalizeXaiSpeechResponseFormat(config.responseFormat)
};
}
function readXaiSpeechOverrides(overrides) {
if (!overrides) return {};
return {
voiceId: normalizeOptionalString(overrides.voiceId ?? overrides.voice),
language: normalizeXaiLanguageCode(overrides.language),
speed: normalizeXaiSpeechSpeed(overrides.speed)
};
}
function resolveDirectXaiAudioApiKey(configApiKey) {
return normalizeOptionalString(configApiKey) ?? normalizeOptionalString(process.env.XAI_API_KEY);
}
function parseXaiSpeechDirectiveToken(ctx) {
switch (ctx.key) {
case "voice":
case "voice_id":
case "voiceid":
case "xai_voice":
case "xaivoice":
if (!ctx.policy.allowVoice) return { handled: true };
if (!isValidXaiTtsVoice(ctx.value)) return {
handled: true,
warnings: [`invalid xAI voice "${ctx.value}"`]
};
return {
handled: true,
overrides: { voiceId: ctx.value }
};
default: return { handled: false };
}
}
function createXaiSpeechProviderMetadata(context) {
return {
id: "xai",
label: "xAI",
autoSelectOrder: 25,
models: [],
voices: XAI_TTS_FALLBACK_VOICES,
resolveConfig: ({ rawConfig }) => normalizeXaiSpeechProviderConfig(rawConfig),
parseDirectiveToken: parseXaiSpeechDirectiveToken,
resolveTalkConfig: ({ baseTtsConfig, talkProviderConfig }) => {
const base = normalizeXaiSpeechProviderConfig(baseTtsConfig);
const responseFormat = normalizeXaiSpeechResponseFormat(talkProviderConfig.responseFormat);
const baseUrl = normalizeOptionalString(talkProviderConfig.baseUrl);
return {
...base,
apiKey: talkProviderConfig.apiKey === void 0 ? base.apiKey : normalizeResolvedSecretInputString({
value: talkProviderConfig.apiKey,
path: "talk.providers.xai.apiKey"
}),
baseUrl: baseUrl === void 0 ? base.baseUrl : normalizeXaiTtsBaseUrl(baseUrl),
voiceId: normalizeOptionalString(talkProviderConfig.voiceId) ?? base.voiceId,
language: normalizeXaiLanguageCode(talkProviderConfig.language ?? talkProviderConfig.languageCode) ?? base.language,
speed: normalizeXaiSpeechSpeed(talkProviderConfig.speed) ?? base.speed,
responseFormat: responseFormat ?? base.responseFormat
};
},
resolveTalkOverrides: ({ params }) => {
const voiceId = normalizeOptionalString(params.voiceId ?? params.voice);
const language = normalizeXaiLanguageCode(params.language ?? params.languageCode);
const speed = normalizeXaiSpeechSpeed(params.speed);
return {
...voiceId === void 0 ? {} : { voiceId },
...language === void 0 ? {} : { language },
...speed === void 0 ? {} : { speed }
};
},
isConfigured: ({ providerConfig, cfg }) => Boolean(resolveDirectXaiAudioApiKey(readXaiSpeechProviderConfig(providerConfig).apiKey)) || context.isProviderAuthProfileConfigured({
provider: "xai",
cfg
})
};
}
//#endregion
export { normalizeXaiTtsBaseUrl as a, resolveDirectXaiAudioApiKey as c, normalizeXaiLanguageCode as i, resolveXaiSpeechResponseFormat as l, createXaiSpeechProviderMetadata as n, readXaiSpeechOverrides as o, isValidXaiTtsVoice as r, readXaiSpeechProviderConfig as s, XAI_TTS_FALLBACK_VOICES as t, xaiSpeechResponseFormatToFileExtension as u };