openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
170 lines (169 loc) • 8 kB
JavaScript
import { c as normalizeOptionalString, i as normalizeFastMode } from "./string-coerce-mnp54Vah.js";
import { c as isRecord } from "./utils-CCC-BEJH.js";
import { o as coerceSecretRef } from "./types.secrets-_0JOMGE5.js";
import { p as normalizeThinkLevel } from "./thinking-OG7pb4lf.js";
//#region src/config/talk.ts
function normalizeTalkSecretInput(value) {
if (typeof value === "string") {
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : void 0;
}
return coerceSecretRef(value) ?? void 0;
}
function normalizeSilenceTimeoutMs(value) {
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) return;
return value;
}
function buildLegacyTalkProviderCompat(value) {
const provider = {};
for (const key of [
"voiceId",
"voiceAliases",
"modelId",
"outputFormat"
]) if (value[key] !== void 0) provider[key] = value[key];
const apiKey = normalizeTalkSecretInput(value.apiKey);
if (apiKey !== void 0) provider.apiKey = apiKey;
return Object.keys(provider).length > 0 ? provider : void 0;
}
function normalizeTalkProviderConfig(value) {
if (!isRecord(value)) return;
const provider = {};
for (const [key, raw] of Object.entries(value)) {
if (raw === void 0) continue;
if (key === "apiKey") {
const normalized = normalizeTalkSecretInput(raw);
if (normalized !== void 0) provider.apiKey = normalized;
continue;
}
provider[key] = raw;
}
return Object.keys(provider).length > 0 ? provider : void 0;
}
function normalizeTalkProviders(value) {
if (!isRecord(value)) return;
const providers = {};
for (const [rawProviderId, providerConfig] of Object.entries(value)) {
const providerId = normalizeOptionalString(rawProviderId);
if (!providerId) continue;
const normalizedProvider = normalizeTalkProviderConfig(providerConfig);
if (!normalizedProvider) continue;
providers[providerId] = {
...providers[providerId],
...normalizedProvider
};
}
return Object.keys(providers).length > 0 ? providers : void 0;
}
function normalizeTalkRealtimeConfig(value) {
if (!isRecord(value)) return;
const source = value;
const normalized = {};
const provider = normalizeOptionalString(source.provider);
if (provider) normalized.provider = provider;
const providers = normalizeTalkProviders(source.providers);
if (providers) normalized.providers = providers;
const model = normalizeOptionalString(source.model);
if (model) normalized.model = model;
const voice = normalizeOptionalString(source.voice);
const speakerVoice = normalizeOptionalString(source.speakerVoice) ?? voice;
const speakerVoiceId = normalizeOptionalString(source.speakerVoiceId);
if (speakerVoice) normalized.speakerVoice = speakerVoice;
if (speakerVoiceId) normalized.speakerVoiceId = speakerVoiceId;
if (voice) normalized.voice = voice;
const instructions = normalizeOptionalString(source.instructions);
if (instructions) normalized.instructions = instructions;
if (source.mode === "realtime" || source.mode === "stt-tts" || source.mode === "transcription") normalized.mode = source.mode;
if (source.transport === "webrtc" || source.transport === "provider-websocket" || source.transport === "gateway-relay" || source.transport === "managed-room") normalized.transport = source.transport;
if (source.brain === "agent-consult" || source.brain === "direct-tools" || source.brain === "none") normalized.brain = source.brain;
if (source.consultRouting === "provider-direct" || source.consultRouting === "force-agent-consult") normalized.consultRouting = source.consultRouting;
return Object.keys(normalized).length > 0 ? normalized : void 0;
}
function activeProviderFromTalk(talk) {
const provider = normalizeOptionalString(talk.provider);
const providers = talk.providers;
if (provider) {
if (providers && !(provider in providers)) return;
return provider;
}
const providerIds = providers ? Object.keys(providers) : [];
return providerIds.length === 1 ? providerIds[0] : void 0;
}
/**
* Normalize persisted Talk config into the canonical provider/providers shape.
* Legacy flat provider fields are ignored here so core config stays provider-agnostic.
*/
function normalizeTalkSection(value) {
if (!isRecord(value)) return;
const source = value;
const normalized = {};
const speechLocale = normalizeOptionalString(source.speechLocale);
if (speechLocale) normalized.speechLocale = speechLocale;
if (typeof source.interruptOnSpeech === "boolean") normalized.interruptOnSpeech = source.interruptOnSpeech;
const consultThinkingLevel = normalizeThinkLevel(normalizeOptionalString(source.consultThinkingLevel));
if (consultThinkingLevel) normalized.consultThinkingLevel = consultThinkingLevel;
const rawConsultFastMode = source.consultFastMode;
const consultFastMode = typeof rawConsultFastMode === "boolean" || typeof rawConsultFastMode === "string" ? normalizeFastMode(rawConsultFastMode) : void 0;
if (consultFastMode !== void 0) normalized.consultFastMode = consultFastMode;
const silenceTimeoutMs = normalizeSilenceTimeoutMs(source.silenceTimeoutMs);
if (silenceTimeoutMs !== void 0) normalized.silenceTimeoutMs = silenceTimeoutMs;
const providers = normalizeTalkProviders(source.providers);
const realtime = normalizeTalkRealtimeConfig(source.realtime);
const provider = normalizeOptionalString(source.provider);
if (providers) normalized.providers = providers;
if (realtime) normalized.realtime = realtime;
if (provider) normalized.provider = provider;
return Object.keys(normalized).length > 0 ? normalized : void 0;
}
/** Return a config copy with `talk` normalized when a valid Talk section is present. */
function normalizeTalkConfig(config) {
if (!config.talk) return config;
const normalizedTalk = normalizeTalkSection(config.talk);
if (!normalizedTalk) return config;
return {
...config,
talk: normalizedTalk
};
}
/**
* Resolve the single active Talk speech provider and its provider-owned config.
* Ambiguous multi-provider config stays unresolved until `talk.provider` names one.
*/
function resolveActiveTalkProviderConfig(talk) {
const normalizedTalk = normalizeTalkSection(talk);
if (!normalizedTalk) return;
const provider = activeProviderFromTalk(normalizedTalk);
if (!provider) return;
return {
provider,
config: normalizedTalk.providers?.[provider] ?? {}
};
}
/**
* Build the gateway `talk.config` payload from persisted config.
* The response includes canonical provider data plus the resolved provider when selection is unambiguous.
*/
function buildTalkConfigResponse(value) {
if (!isRecord(value)) return;
const normalized = normalizeTalkSection(value);
const legacyCompat = buildLegacyTalkProviderCompat(value);
if (!normalized && !legacyCompat) return;
const payload = {};
if (typeof normalized?.interruptOnSpeech === "boolean") payload.interruptOnSpeech = normalized.interruptOnSpeech;
if (typeof normalized?.silenceTimeoutMs === "number") payload.silenceTimeoutMs = normalized.silenceTimeoutMs;
if (typeof normalized?.consultThinkingLevel === "string") payload.consultThinkingLevel = normalized.consultThinkingLevel;
if (typeof normalized?.consultFastMode === "boolean") payload.consultFastMode = normalized.consultFastMode;
if (typeof normalized?.speechLocale === "string") payload.speechLocale = normalized.speechLocale;
if (normalized?.providers && Object.keys(normalized.providers).length > 0) payload.providers = normalized.providers;
if (normalized?.realtime && Object.keys(normalized.realtime).length > 0) payload.realtime = normalized.realtime;
const resolved = resolveActiveTalkProviderConfig(normalized) ?? (legacyCompat ? {
provider: "elevenlabs",
config: legacyCompat
} : void 0);
const activeProvider = resolved?.provider;
if (activeProvider) payload.provider = activeProvider;
if (resolved) payload.resolved = resolved;
return Object.keys(payload).length > 0 ? payload : void 0;
}
//#endregion
export { resolveActiveTalkProviderConfig as i, normalizeTalkConfig as n, normalizeTalkSection as r, buildTalkConfigResponse as t };