Text-to-Speech for Outbound Replies: Providers, Config, and Commands
This page covers OpenClaw's text-to-speech system for outbound replies, including 14 supported providers, per-channel output, and slash commands. It is intended for users configuring TTS for voice replies across platforms.
Read this when
- Enabling text-to-speech for replies
- Configuring a TTS provider, fallback chain, or persona
- Using /tts commands or directives
OpenClaw turns outbound replies into spoken audio using 14 different speech providers: native voice messages on Feishu, Matrix, Telegram, and WhatsApp; audio file attachments for all other platforms; and PCM/Ulaw streams for telephony and Talk.
TTS handles the speech generation side of Talk's stt-tts mode (talk.speak uses this same synthesis pipeline). Provider-native realtime Talk sessions produce speech directly within the realtime provider; transcription sessions never generate an assistant voice reply.
Quick start
Pick a provider
For hosted solutions, OpenAI and ElevenLabs offer the greatest reliability. Microsoft and Local CLI function without requiring an API key. The full provider list is available in the provider matrix.
Set the API key
Set the environment variable for your chosen provider (for example OPENAI_API_KEY, ELEVENLABS_API_KEY). Microsoft and Local CLI do not need a key.
Enable in config
Configure tts.auto: "always" and tts.provider:
{
tts: {
auto: "always",
provider: "elevenlabs",
},
}
Try it in chat
/tts status displays the current status. /tts audio Hello from OpenClaw triggers a single audio reply.
Note
Auto-TTS is disabled by default. When
tts.provideris not set, OpenClaw selects the first configured provider based on the registry auto-select order. The built-inttsagent tool only responds to explicit intent: regular chat remains text-based unless the user requests audio, uses/tts, or activates Auto-TTS or directive speech.
Supported providers
| Provider | Auth | Notes |
|---|---|---|
| Azure Speech | AZURE_SPEECH_KEY + AZURE_SPEECH_REGION (also AZURE_SPEECH_API_KEY, SPEECH_KEY, SPEECH_REGION) | Native Ogg/Opus voice-note output and telephony. |
| DeepInfra | DEEPINFRA_API_KEY | OpenAI-compatible TTS. Defaults to hexgrad/Kokoro-82M. |
| ElevenLabs | ELEVENLABS_API_KEY or XI_API_KEY | Voice cloning, multilingual, deterministic via seed; streamed for Discord voice playback. |
| Google Gemini | GEMINI_API_KEY or GOOGLE_API_KEY | Gemini API batch TTS; persona-aware via promptTemplate: "audio-profile-v1". |
| Gradium | GRADIUM_API_KEY | Voice-note and telephony output. |
| Inworld | INWORLD_API_KEY | Streaming TTS API. Native Opus voice-note and PCM telephony. |
| Local CLI | none | Runs a configured local TTS command. |
| Microsoft | none | Public Edge neural TTS via node-edge-tts. Best-effort, no SLA. |
| MiniMax | MINIMAX_API_KEY (or Token Plan: MINIMAX_OAUTH_TOKEN, MINIMAX_CODE_PLAN_KEY, MINIMAX_CODING_API_KEY) | T2A v2 API. Defaults to speech-2.8-hd. |
| OpenAI | OPENAI_API_KEY | Also used for auto-summary; supports persona instructions. |
| OpenRouter | OPENROUTER_API_KEY (can reuse models.providers.openrouter.apiKey) | Default model hexgrad/kokoro-82m. |
| Volcengine | VOLCENGINE_TTS_API_KEY or BYTEPLUS_SEED_SPEECH_API_KEY (legacy AppID/token: VOLCENGINE_TTS_APPID/_TOKEN) | BytePlus Seed Speech HTTP API. |
| Vydra | VYDRA_API_KEY | Shared image, video, and speech provider. |
| xAI | XAI_API_KEY | xAI batch TTS. Native Opus voice-note is not supported. |
| Xiaomi MiMo | XIAOMI_API_KEY | MiMo TTS through Xiaomi chat completions. |
When multiple providers are configured, the selected one takes priority and the rest act as fallbacks. Auto-summary uses summaryModel (or agents.defaults.model.primary), so that provider must also have valid authentication if summaries remain enabled.
Caution
The included Microsoft provider relies on Microsoft Edge's cloud-based neural TTS endpoint at
node-edge-tts. This is a publicly accessible web service with no documented SLA or rate limits, so consider it best-effort only. The older provider identifieredgegets normalized tomicrosoft, andopenclaw doctor --fixupdates saved configuration; any new setup should usemicrosoftgoing forward.
Configuration
TTS configuration is stored under tts inside ~/.openclaw/openclaw.json. Choose a
preset and customize the provider section. The speakerVoice and speakerVoiceId
fields listed here are the standard ones; each provider's original voice, voiceId,
and voiceName field names remain usable as backward-compatible alternatives.
Azure Speech
{
tts: {
auto: "always",
provider: "azure-speech",
providers: {
"azure-speech": {
apiKey: "${AZURE_SPEECH_KEY}",
region: "eastus",
speakerVoice: "en-US-JennyNeural",
lang: "en-US",
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
voiceNoteOutputFormat: "ogg-24khz-16bit-mono-opus",
},
},
},
}
ElevenLabs
{
tts: {
auto: "always",
provider: "elevenlabs",
providers: {
elevenlabs: {
apiKey: "${ELEVENLABS_API_KEY}",
model: "eleven_multilingual_v2",
speakerVoiceId: "EXAVITQu4vr4xnSDxMaL",
},
},
},
}
Google Gemini
{
tts: {
auto: "always",
provider: "google",
providers: {
google: {
apiKey: "${GEMINI_API_KEY}",
model: "gemini-3.1-flash-tts-preview",
speakerVoice: "Kore",
// Optional natural-language style prompts:
// audioProfile: "Speak in a calm, podcast-host tone.",
// speakerName: "Alex",
},
},
},
}
Gradium
{
tts: {
auto: "always",
provider: "gradium",
providers: {
gradium: {
apiKey: "${GRADIUM_API_KEY}",
speakerVoiceId: "YTpq7expH9539ERJ",
},
},
},
}
Inworld
{
tts: {
auto: "always",
provider: "inworld",
providers: {
inworld: {
apiKey: "${INWORLD_API_KEY}",
modelId: "inworld-tts-1.5-max",
speakerVoiceId: "Sarah",
temperature: 0.7,
},
},
},
}
Local CLI
{
tts: {
auto: "always",
provider: "tts-local-cli",
providers: {
"tts-local-cli": {
command: "say",
args: ["-o", "{{OutputPath}}", "{{Text}}"],
outputFormat: "wav",
timeoutMs: 120000,
},
},
},
}
Microsoft (no key)
{
tts: {
auto: "always",
provider: "microsoft",
providers: {
microsoft: {
enabled: true,
speakerVoice: "en-US-MichelleNeural",
lang: "en-US",
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
rate: "+0%",
pitch: "+0%",
},
},
},
}
MiniMax
{
tts: {
auto: "always",
provider: "minimax",
providers: {
minimax: {
apiKey: "${MINIMAX_API_KEY}",
model: "speech-2.8-hd",
speakerVoiceId: "English_expressive_narrator",
speed: 1.0,
vol: 1.0,
pitch: 0,
},
},
},
}
OpenAI + ElevenLabs
{
tts: {
auto: "always",
provider: "openai",
summaryModel: "openai/gpt-4.1-mini",
modelOverrides: { enabled: true },
providers: {
openai: {
apiKey: "${OPENAI_API_KEY}",
model: "gpt-4o-mini-tts",
speakerVoice: "alloy",
},
elevenlabs: {
apiKey: "${ELEVENLABS_API_KEY}",
model: "eleven_multilingual_v2",
speakerVoiceId: "EXAVITQu4vr4xnSDxMaL",
voiceSettings: { stability: 0.5, similarityBoost: 0.75, style: 0.0, useSpeakerBoost: true, speed: 1.0 },
applyTextNormalization: "auto",
languageCode: "en",
},
},
},
}
OpenRouter
{
tts: {
auto: "always",
provider: "openrouter",
providers: {
openrouter: {
apiKey: "${OPENROUTER_API_KEY}",
model: "hexgrad/kokoro-82m",
speakerVoice: "af_alloy",
responseFormat: "mp3",
},
},
},
}
Volcengine
{
tts: {
auto: "always",
provider: "volcengine",
providers: {
volcengine: {
apiKey: "${VOLCENGINE_TTS_API_KEY}",
resourceId: "seed-tts-1.0",
speakerVoice: "en_female_anna_mars_bigtts",
},
},
},
}
xAI
{
tts: {
auto: "always",
provider: "xai",
providers: {
xai: {
apiKey: "${XAI_API_KEY}",
speakerVoiceId: "eve",
language: "en",
responseFormat: "mp3",
},
},
},
}
Xiaomi MiMo
{
tts: {
auto: "always",
provider: "xiaomi",
providers: {
xiaomi: {
apiKey: "${XIAOMI_API_KEY}",
model: "mimo-v2.5-tts",
speakerVoice: "mimo_default",
format: "mp3",
},
},
},
}
For Xiaomi mimo-v2.5-tts-voicedesign, leave out speakerVoice and assign style to
the voice design prompt. OpenClaw forwards that prompt as the TTS user message
and does not send audio.voice for the voicedesign model.
Per-agent voice overrides
Apply agents.entries.*.tts when a single agent needs to talk using a different provider,
voice, model, persona, or auto-TTS mode. The agent block deep-merges on top of
tts, so provider credentials can remain in the global provider configuration:
{
tts: {
auto: "always",
provider: "elevenlabs",
providers: {
elevenlabs: { apiKey: "${ELEVENLABS_API_KEY}", model: "eleven_multilingual_v2" },
},
},
agents: {
list: [
{
id: "reader",
tts: {
providers: {
elevenlabs: { speakerVoiceId: "EXAVITQu4vr4xnSDxMaL" },
},
},
},
],
},
}
To lock a per-agent persona, configure agents.entries.*.tts.persona together with the provider
settings. This overrides the global tts.persona for just that agent.
Priority order for automatic replies, /tts audio, /tts status, and the
tts agent tool:
tts- active
agents.entries.*.tts - channel override, provided the channel supports
channels.<channel>.tts - account override, when the channel sends
channels.<channel>.accounts.<id>.tts - local
/ttspreferences on this host - inline
[[tts:...]]directives if model overrides are turned on
Channel and account overrides follow the same structure as tts and
deep-merge over earlier layers. This lets shared provider credentials stay in
tts while a channel or bot account changes only the speaker voice, model, persona,
or auto mode:
{
tts: {
provider: "openai",
providers: {
openai: { apiKey: "${OPENAI_API_KEY}", model: "gpt-4o-mini-tts" },
},
},
channels: {
feishu: {
accounts: {
english: {
tts: {
providers: {
openai: { speakerVoice: "shimmer" },
},
},
},
},
},
},
}
Personas
A persona represents a consistent spoken identity that can be assigned deterministically across different providers. It may favor one provider, define provider-neutral prompt intent, and include provider-specific mappings for voices, models, prompt templates, seeds, and voice parameters.
Minimal persona
{
tts: {
auto: "always",
persona: "narrator",
personas: {
narrator: {
label: "Narrator",
provider: "elevenlabs",
providers: {
elevenlabs: {
speakerVoiceId: "EXAVITQu4vr4xnSDxMaL",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
}
Full persona (provider-specific shaping)
{
tts: {
auto: "always",
persona: "alfred",
personas: {
alfred: {
label: "Alfred",
description: "Dry, warm British butler narrator.",
provider: "google",
fallbackPolicy: "preserve-persona",
providers: {
google: {
model: "gemini-3.1-flash-tts-preview",
speakerVoice: "Algieba",
promptTemplate: "audio-profile-v1",
},
openai: { model: "gpt-4o-mini-tts", speakerVoice: "cedar" },
elevenlabs: {
speakerVoiceId: "voice_id",
modelId: "eleven_multilingual_v2",
seed: 42,
voiceSettings: {
stability: 0.65,
similarityBoost: 0.8,
style: 0.25,
useSpeakerBoost: true,
speed: 0.95,
},
},
},
},
},
},
}
Persona resolution
The active persona is chosen deterministically:
/tts persona <id>local preference, if set.tts.persona, if set.- No persona.
Provider selection follows an explicit-first approach:
- Direct overrides (CLI, gateway, Talk, allowed TTS directives).
/tts provider <id>local preference.- Active persona's
provider. tts.provider.- Registry auto-select.
When trying each provider, OpenClaw applies configurations in this sequence:
tts.providers.<id>tts.personas.<persona>.providers.<id>- Trusted request overrides
- Allowed model-emitted TTS directive overrides
Custom persona shaping
The provider-neutral personas.<id>.prompt.* config has been deprecated. Doctor removes
those fields and redirects them to the speech-provider seam. Place built-in provider
settings inside personas.<id>.providers.<provider> (for instance Google
personaPrompt or OpenAI instructions). For custom behavior, write a
speech provider plugin using prepareSynthesis(ctx) and hand back modified text,
provider config, or overrides before synthesize() executes. This keeps expressive
prompt construction in provider code where request semantics are understood.
Fallback policy
fallbackPolicy decides what happens when a persona has no binding for the
provider being tried:
| Policy | Behavior |
|---|---|
preserve-persona | Default. Provider-neutral prompt fields remain accessible; the provider can use them or disregard them. |
provider-defaults | That persona is left out of prompt preparation for this attempt; the provider uses its neutral defaults while fallback to other providers proceeds. |
fail | Skip that provider attempt with reasonCode: "not_configured" and personaBinding: "missing". Fallback providers are still attempted. |
The entire TTS request fails only when every attempted provider is skipped or fails.
Talk session provider selection applies per session. A Talk client should pick
provider ids, model ids, voice ids, and locales from talk.catalog and send
them through the Talk session or handoff request. Opening a voice session should
not change tts or global Talk provider defaults.
Model-driven directives
By default, the assistant can emit [[tts:...]] directives to override
voice, model, or speed for a single reply, plus an optional
[[tts:text]]...[[/tts:text]] block for expressive cues that should appear in
audio only:
Here you go.
[[tts:speakerVoiceId=pMsXgVXv3BLzUgSXRplE model=eleven_v3 speed=1.1]]
[[tts:text]](laughs) Read the song once more.[[/tts:text]]
When tts.auto is "tagged", directives are required to trigger
audio. Streaming block delivery strips directives from visible text before the
channel sees them, even when split across adjacent blocks.
provider=... is ignored unless modelOverrides.allowProvider: true. When a
reply declares provider=..., the other keys in that directive are parsed
only by that provider; unsupported keys are stripped and reported as TTS
directive warnings.
Available directive keys:
provider(registered provider id; requiresallowProvider: true)speakerVoice/speakerVoiceId(legacy aliases:voice,voiceName,voice_name,google_voice,voiceId)model/google_modelstability,similarityBoost,style,speed,useSpeakerBoostvol/volume(MiniMax volume,(0, 10])pitch(MiniMax integer pitch, −12 to 12; fractional values are truncated)emotion(Volcengine emotion tag)applyTextNormalization(auto|on|off)languageCode(ISO 639-1)seed
Disable model overrides entirely:
{ messages: { tts: { modelOverrides: { enabled: false } } } }
Allow provider switching while keeping other knobs configurable:
{ messages: { tts: { modelOverrides: { enabled: true, allowProvider: true, allowSeed: false } } } }
Slash commands
A single command is available as /tts. On Discord, OpenClaw also registers /voice because /tts is a built-in Discord command. The text version /tts ... remains functional.
/tts off | on | status
/tts chat on | off | default
/tts latest
/tts provider <id>
/tts persona <id> | off
/tts limit <chars>
/tts summary off
/tts audio <text>
Note
Commands need an authorized sender (subject to allowlist/owner rules) and either
commands.textor native command registration must be turned on.
Behavior notes:
/tts onstores the local TTS preference inalways;/tts offstores it inoff./tts chat on|off|defaultwrites a session-scoped auto-TTS override for the current conversation./tts persona <id>stores the local persona preference;/tts persona offremoves it./tts latestretrieves the most recent assistant reply from the current session transcript and plays it as audio once. Only a hash of that reply is saved on the session entry to prevent duplicate voice delivery./tts audiocreates a one-off audio reply without toggling TTS on or off./tts limit <chars>accepts values from 100 to 4096 (4096 is the Telegram caption/message maximum); anything outside that range is rejected.limitandsummaryreside in local prefs, not the main configuration./tts statusprovides fallback diagnostics for the most recent attempt:Fallback: <primary> -> <used>,Attempts: ..., and per-attempt details (provider:outcome(reasonCode) latency)./statusdisplays the active TTS mode along with the configured provider, model, voice, and sanitized custom endpoint metadata when TTS is enabled.
Per-user preferences
Slash commands write local overrides to the TTS preferences path. The default is ~/.openclaw/settings/tts.json; override it with OPENCLAW_TTS_PREFS. Doctor moves the retired global tts.prefsPath value into shared machine state. Advanced multi-agent setups may still set agents.entries.<id>.tts.prefsPath when agents deliberately use separate preference stores.
| Stored field | Effect |
|---|---|
auto | Local auto-TTS override (always, off, …) |
provider | Local primary provider override |
persona | Local persona override |
maxLength | Summary/truncation threshold (default 1500 chars, /tts limit range 100, 4096) |
summarize | Summary toggle (default true) |
These override the effective configuration from tts plus the active agents.entries.*.tts block for that host.
Output formats
TTS voice delivery depends on channel capabilities. Channel plugins indicate whether voice-style TTS should request a native voice-note target from providers or keep standard audio-file synthesis, and whether the channel transcodes non-native output before delivery.
| Target | Format |
|---|---|
| Feishu / Matrix / Telegram / WhatsApp | Voice-note replies prefer Opus (opus_48000_64 from ElevenLabs, opus from OpenAI). 48 kHz / 64 kbps balances clarity and size. |
| Other channels | MP3 (mp3_44100_128 from ElevenLabs, mp3 from OpenAI). 44.1 kHz / 128 kbps is the default balance for speech. |
| Talk / telephony | Provider-native PCM (Inworld 22050 Hz, Google 24 kHz), or ulaw_8000 from Gradium for telephony. |
Per-provider notes:
- Feishu / WhatsApp transcoding: When a voice note reply comes in as MP3, WebM, WAV, M4A, or another probable audio format, the channel plugin converts it to 48 kHz Ogg/Opus using
ffmpeg(libopus, 64 kbps) before dispatching the native voice message. WhatsApp transmits the result through the Baileysaudiopayload withptt: trueandaudio/ogg; codecs=opus. If transcoding fails: Feishu catches the error and reverts to sending the original file as a plain attachment; WhatsApp has no fallback, so the send itself fails instead of delivering an incompatible PTT payload. - MiniMax: MP3 (
speech-2.8-hdmodel, 32 kHz sample rate) for standard audio attachments; converted to 48 kHz Opus withffmpegfor channel-advertised voice note targets. - Xiaomi MiMo: MP3 by default, or WAV when configured; converted to 48 kHz Opus with
ffmpegfor channel-advertised voice note targets. - Local CLI: uses the configured
outputFormat. Voice note targets are transformed to Ogg/Opus and telephony output is converted to raw 16 kHz mono PCM withffmpeg. - Google Gemini: returns raw 24 kHz PCM. OpenClaw packages it as WAV for audio attachments, converts it to 48 kHz Opus for voice note targets, and returns PCM directly for Talk/telephony.
- Gradium: WAV for audio attachments, Opus for voice note targets, and
ulaw_8000at 8 kHz for telephony. - Inworld: MP3 for normal audio attachments, native
OGG_OPUSfor voice note targets, and rawPCMat 22050 Hz for Talk/telephony. - xAI: MP3 by default; audio file synthesis may use
mp3,wav,pcm,mulaw, oralawfor both buffered and streaming output. Voice note targets use MP3 for streaming and buffered fallback because xAI'spcm,mulaw, andalawoutputs are headerless raw audio. Buffered synthesis uses xAI's batch REST/v1/ttsendpoint;textToSpeechStreamuses nativewss://api.x.ai/v1/tts. This is not the realtime voice contract. Native Opus voice note format is not supported. - Microsoft: uses
microsoft.outputFormat(defaultaudio-24khz-48kbitrate-mono-mp3).- The bundled transport accepts an
outputFormat, but not all formats are available from the service. - Output format values follow Microsoft Speech output formats (including Ogg/WebM Opus).
- Telegram
sendVoiceaccepts OGG/MP3/M4A; use OpenAI/ElevenLabs if you need guaranteed Opus voice messages. - If the configured Microsoft output format fails, OpenClaw retries with MP3.
- When no explicit voice override is set and the default English voice is used, OpenClaw auto-switches to a Chinese neural voice (
zh-CN-XiaoxiaoNeural,zh-CNlocale) if the reply text is CJK-dominant.
- The bundled transport accepts an
OpenAI and ElevenLabs output formats are fixed per channel as listed above.
Auto-TTS behavior
When tts.auto is enabled, OpenClaw:
- Skips TTS if the reply already contains structured media.
- Skips very short replies (under 10 chars).
- Summarizes long replies when summaries are enabled, using
summaryModel(oragents.defaults.model.primary). - Attaches the generated audio to the reply.
- In
mode: "final", still sends audio-only TTS for streamed final replies after the text stream completes; the generated media goes through the same channel media normalization as normal reply attachments.
If the reply exceeds maxLength, OpenClaw never skips audio outright:
- Summary on (default) and a summary model is available: summarizes the
text to roughly
maxLengthchars, then synthesizes the summary. - Summary off, summarization fails, or no API key is available for the
summary model: truncates the text to
maxLengthchars and synthesizes the truncated text.
Reply -> TTS enabled?
no -> send text
yes -> has media / short?
yes -> send text
no -> length > limit?
no -> TTS -> attach audio
yes -> summary enabled and available?
no -> truncate -> TTS -> attach audio
yes -> summarize -> TTS -> attach audio
Field reference
Top-level tts.*
-
auto(off" | "always" | "inbound" | "tagged), Auto-TTS mode.inboundonly sends audio after an inbound voice message;taggedonly sends audio when the reply includes[[tts:...]]directives or a[[tts:text]]block. -
enabled(boolean), Legacy toggle.openclaw doctor --fixmigrates this toauto. -
mode(final" | "all, default: final),"all"includes tool/block replies in addition to final replies. -
provider(string), Speech provider id. When unset, OpenClaw uses the first configured provider in registry auto-select order. Legacyprovider: "edge"is rewritten to"microsoft"byopenclaw doctor --fix. -
persona(string), Active persona id frompersonas. Normalized to lowercase. -
true, " type="object"> A consistent vocal identity. Contains these fields:label,description,provider,fallbackPolicy,prompt,providers.<provider>. Refer to Personas. -
summaryModel(string), An inexpensive model intended for auto-summarization;agents.defaults.model.primaryis the default. Eitherprovider/modelor a configured model alias is accepted. -
modelOverrides(object), Permits the model to issue TTS instructions.enabledhas a default oftrue;allowProviderdefaults tofalse. -
true, " type="object"> Provider-specific settings, organized by speech provider identifier. Legacy direct blocks (tts.openai,.elevenlabs,.microsoft,.edge) are converted byopenclaw doctor --fix; onlytts.providers.<id>should be committed. -
maxTextLength(number, default: 4096), The maximum number of characters allowed for TTS input. Requests exceeding this limit cause/tts audio,tts.convert, andtts.speakto fail. -
timeoutMs(number, default: 30000), Timeout for requests, expressed in milliseconds. A per-calltimeoutMs(agent tool, gateway) takes precedence when provided; otherwise, an explicitly configuredtts.timeoutMsoverrides any plugin-defined provider default.
Provider apiKey fields may be either plain strings or SecretRefs. During a cold Gateway startup, if a TTS SecretRef is unavailable, the built-in TTS capability is marked as configured-unavailable rather than halting the Gateway. tts.speak then returns UNAVAILABLE with reason SECRET_SURFACE_UNAVAILABLE, and no provider request is dispatched. The status and doctor list show the degraded TTS owner along with its configuration paths. The explicit refs stay in the runtime snapshot, preventing environment or profile credentials from silently selecting a different account. Reloads and config-write preflight checks apply an owner-aware degradation policy: an unchanged eligible TTS owner may retain its last-known-good credentials as stale, whereas a new or changed failure becomes cold without blocking healthy owners. Structurally invalid refs and resolved values still cause startup to fail or the update to be rejected.
Azure Speech
-
apiKey(string), Environment variable:AZURE_SPEECH_KEY,AZURE_SPEECH_API_KEY, orSPEECH_KEY. -
region(string), The Azure Speech region (for example,eastus). Environment variable:AZURE_SPEECH_REGIONorSPEECH_REGION. -
endpoint(string), An optional override for the Azure Speech endpoint (aliasbaseUrl). -
speakerVoice(string), The ShortName of the Azure voice. Default isen-US-JennyNeural. Legacy alias:voice. -
lang(string), The SSML language code. Default isen-US. -
outputFormat(string), The AzureX-Microsoft-OutputFormatfor standard audio output. Default isaudio-24khz-48kbitrate-mono-mp3. -
voiceNoteOutputFormat(string), The AzureX-Microsoft-OutputFormatfor voice-note output. Default isogg-24khz-16bit-mono-opus.ElevenLabs
-
apiKey(string), Falls back toELEVENLABS_API_KEYorXI_API_KEY. -
model(string), Identifies the model. Falls back toeleven_multilingual_v2. Older identifierseleven_turbo_v2_5andeleven_turbo_v2get mapped to the correspondingflashmodel automatically. -
speakerVoiceId(string), The ElevenLass voice identifier. UsespMsXgVXv3BLzUgSXRplEby default. An older name for this isvoiceId. -
voiceSettings(object), Containsstability,similarityBoost,style(each one is0..1, with defaults0.5,0.75,0),useSpeakerBoost(typetrue|false, defaulttrue), andspeed(type0.5..2.0, default1.0). -
applyTextNormalization(auto" | "on" | "off), Controls how text normalization is applied. -
languageCode(string), A two-letter code from ISO 639-1, for instanceenorde. -
seed(number), An integer0..4294967295used to attempt deterministic behavior. -
baseUrl(string), Lets you replace the default ElevenLabs API base URL.Google Gemini
-
apiKey(string), TriesGEMINI_API_KEYandGOOGLE_API_KEYas fallbacks. When not provided, TTS may reusemodels.providers.google.apiKeybefore checking environment variables. -
model(string), The Gemini TTS model to use. Defaults togemini-3.1-flash-tts-preview. -
speakerVoice(string), A prebuilt voice name from Gemini. Default isKore. Older names includevoiceNameandvoice. -
audioProfile(string), A style prompt in natural language that gets inserted before the spoken content. -
speakerName(string), An optional speaker tag placed before the spoken text when your prompt references a specific speaker. -
promptTemplate(audio-profile-v1), Set toaudio-profile-v1to enclose active persona prompt fields inside a fixed Gemini TTS prompt template. -
personaPrompt(string), Extra persona prompt text specific to Google, appended to the Director's Notes section of the template. -
baseUrl(string), Onlyhttps://generativelanguage.googleapis.comis allowed here.Gradium
-
apiKey(string), Read from the environment variableGRADIUM_API_KEY. -
baseUrl(string), A Gradium API URL over HTTPS onapi.gradium.ai. Defaults tohttps://api.gradium.ai. -
speakerVoiceId(string), Defaults to Emma (YTpq7expH9539ERJ). The older namevoiceIdstill works.Inworld
Inworld primary
-
apiKey(string), Sourced from the environment variableINWORLD_API_KEY. -
baseUrl(string), Falls back tohttps://api.inworld.ai. -
modelId(string), Falls back toinworld-tts-1.5-max. Options includeinworld-tts-1.5-mini,inworld-tts-1-max, andinworld-tts-1. -
speakerVoiceId(string), Falls back toSarah. Previously known asvoiceId. -
temperature(number), Sampling temperature0..2(0 is excluded).Local CLI (tts-local-cli)
-
command(string), Path to a local binary or a command string used for CLI-based TTS. -
args(string[]), Arguments passed to the command. Accepts{{Text}},{{OutputPath}},{{OutputDir}}, and{{OutputBase}}as placeholders. -
outputFormat(mp3" | "opus" | "wav), The audio format the CLI is expected to output. When attaching audio,mp3is the default. -
timeoutMs(number), How long (in milliseconds) to wait before the command times out. Defaults to120000. -
cwd(string), An optional directory to run the command from. -
env(true), ">Optional environment variables that override the command's environment.Any audio produced by the command's stdout, or converted from it, must stay under 50 MiB. Diagnostic stderr output is capped at 1 MiB. If either limit is exceeded, OpenClaw kills the command and reports a synthesis failure.
Microsoft (no API key)
-
enabled(boolean, default: true), Whether to allow speech generation through Microsoft. -
**
speakerVoice(string), Name of a Microsoft neural voice (for instance,en-US-MichelleNeural). The legacy name isvoice. When the default English voice is active and the reply text is mostly CJK, OpenClaw automatically switches tozh-CN-XiaoxiaoNeural. -
lang(string), Language identifier (for example,en-US). -
outputFormat(string), Output format used by Microsoft. Defaults toaudio-24khz-48kbitrate-mono-mp3. The bundled Edge transport does not support every format. -
rate / pitch / volume(string), Percent strings, such as+10%or-5%. -
saveSubtitles(boolean), Whether to write JSON subtitle files alongside the audio output. -
proxy(string), Proxy address for Microsoft speech API calls. -
timeoutMs(number), Request timeout override, in milliseconds. -
edge.*(object), Legacy name. Runopenclaw doctor --fixto migrate stored configuration toproviders.microsoft.MiniMax
-
apiKey(string), Falls back toMINIMAX_API_KEY. Token Plan authentication usesMINIMAX_OAUTH_TOKEN,MINIMAX_CODE_PLAN_KEY, orMINIMAX_CODING_API_KEY. -
baseUrl(string), Defaults tohttps://api.minimax.io. Can be set via theMINIMAX_API_HOSTenvironment variable. -
model(string), Defaults tospeech-2.8-hd. Can be set via theMINIMAX_TTS_MODELenvironment variable. -
speakerVoiceId(string), Defaults toEnglish_expressive_narrator. Can be set via theMINIMAX_TTS_VOICE_IDenvironment variable. Previously known asvoiceId. -
speed(number),0.5..2.0. The default is1.0. -
vol(number),(0, 10]. Falls back to1.0by default. -
pitch(number), An integer-12..12. Defaults to0. Any fractional component gets removed before the request is sent.OpenAI
-
apiKey(string), If not provided,OPENAI_API_KEYis used instead. -
model(string), The model identifier for the OpenAI TTS service. Defaults togpt-4o-mini-tts. -
speakerVoice(string), The name of the voice to use (for instance,alloyorcedar). Default iscoral. The older name for this setting isvoice. -
instructions(string), Directly sets the OpenAIinstructionsfield. When this is configured, persona prompt fields are not mapped automatically. -
extraBody / extra_body(true), ">Additional JSON fields inserted into/audio/speechrequest bodies after the auto-generated OpenAI TTS fields. This is useful for OpenAI-compatible endpoints such as Kokoro that need provider-specific keys likelang. Unsafe prototype keys are ignored. -
baseUrl(string), Replaces the default OpenAI TTS endpoint. The system checks this config first, thenOPENAI_TTS_BASE_URL, thenhttps://api.openai.com/v1. Non-default values are handled as OpenAI-compatible TTS endpoints, so custom model and voice names are allowed, andspeedno longer enforces the0.25..4.0range check.OpenRouter
-
apiKey(string), Environment variable:OPENROUTER_API_KEY. Can also reusemodels.providers.openrouter.apiKey. -
baseUrl(string), Default ishttps://openrouter.ai/api/v1. The olderhttps://openrouter.ai/v1value gets normalized. -
model(string), Defaults tohexgrad/kokoro-82m. Also known asmodelId. -
speakerVoice(string), Default isaf_alloy. Older names for this setting:voiceandvoiceId. -
responseFormat(mp3" | "pcm), Defaults tomp3. -
speed(number), A speed adjustment that is native to the provider.Volcengine (BytePlus Seed Speech)
-
apiKey(string), Environment variable:VOLCENGINE_TTS_API_KEYorBYTEPLUS_SEED_SPEECH_API_KEY. -
resourceId(string), Default isseed-tts-1.0. Environment variable:VOLCENGINE_TTS_RESOURCE_ID. When your project has a TTS 2.0 entitlement, useseed-tts-2.0. -
appKey(string), The header for the app key. Default isaGjiRDfUWi. Environment variable:VOLCENGINE_TTS_APP_KEY. -
baseUrl(string), Replaces the Seed Speech TTS HTTP endpoint. Environment variable:VOLCENGINE_TTS_BASE_URL.
-
speakerVoice(string), Determines the voice type. Defaults toen_female_anna_mars_bigtts. Can be set via theVOLCENGINE_TTS_VOICEenvironment variable. Previously known asvoice. -
speedRatio(number), A speed multiplier specific to the provider, with a value of0.2..3. -
emotion(string), An emotion tag defined by the provider. -
appId / token / cluster(string), Fields inherited from the older Volcengine Speech Console. Configured through environment variablesVOLCENGINE_TTS_APPID,VOLCENGINE_TTS_TOKEN, andVOLCENGINE_TTS_CLUSTER(the last defaults tovolcano_tts).
xAI
-
apiKey(string), Set via theXAI_API_KEYenvironment variable. -
baseUrl(string), Defaults tohttps://api.x.ai/v1. Configurable with theXAI_BASE_URLenvironment variable. -
speakerVoiceId(string), Defaults toeve. When authentication is provided,openclaw infer tts voices --provider xairetrieves the current built-in catalog; without it, the system lists offline fallbacks:ara,eve,leo,rex, andsal. Custom voice IDs from the account are forwarded even if they do not appear in the built-in list. Its legacy name isvoiceId. -
language(string), A BCP-47 language code, orauto. The default isen. -
responseFormat(mp3" | "wav" | "pcm" | "mulaw" | "alaw), Defaults tomp3. -
speed(number), A provider-specific speed adjustment, set to0.7..1.5.
Xiaomi MiMo
-
apiKey(string), Configured via theXIAOMI_API_KEYenvironment variable. -
baseUrl(string), Defaults tohttps://api.xiaomimimo.com/v1. Set using theXIAOMI_BASE_URLenvironment variable. -
model(string), Defaults tomimo-v2.5-tts. Configurable with theXIAOMI_TTS_MODELenvironment variable. Also acceptsmimo-v2.5-tts-voicedesign. -
speakerVoice(string), For preset-voice models, the default ismimo_default. Set via theXIAOMI_TTS_VOICEenvironment variable. Its legacy alias isvoice. This value is not sent formimo-v2.5-tts-voicedesign. -
format(mp3" | "wav), Defaults tomp3. Configurable with theXIAOMI_TTS_FORMATenvironment variable. -
style(string), An optional natural-language style instruction sent as the user message; it is not spoken. Formimo-v2.5-tts-voicedesign, this serves as the voice-design prompt, and OpenClaw provides a default if one is not given.
Agent tool
The tts tool converts text into speech and returns an audio attachment for the reply. On Feishu, Matrix, Telegram, and WhatsApp, the audio is sent as a voice message rather than a file. When ffmpeg is available, Feishu and WhatsApp can transcode non-Opus TTS output along this path.
On WhatsApp, audio is sent through Baileys as a PTT voice note (audio with ptt: true), and visible text is delivered separately from the PTT audio because clients do not reliably render captions on voice notes.
The tool can take optional channel and timeoutMs fields; timeoutMs sets a per-call provider request timeout in milliseconds. Values provided per call override tts.timeoutMs; any TTS timeout configured here takes precedence over a plugin defined provider default.
Gateway RPC
| Method | Purpose |
|---|---|
tts.status | Retrieve the current TTS state and details of the last attempt. |
tts.enable | Change the local auto preference to always. |
tts.disable | Switch the local auto preference to off. |
tts.convert | Convert text to audio in a single request. |
tts.setProvider | Update the local provider preference. |
tts.personas | Show all configured personas and identify which one is active. |
tts.setPersona | Adjust the local persona preference. |
tts.providers | Display all configured providers along with their status. |
Service links
- OpenAI text-to-speech guide
- OpenAI Audio API reference
- Azure Speech REST text-to-speech
- Azure Speech provider
- ElevenLabs Text to Speech
- ElevenLabs Authentication
- Gradium
- Inworld TTS API
- MiniMax T2A v2 API
- Volcengine TTS HTTP API
- Xiaomi MiMo speech synthesis
- node-edge-tts
- Microsoft Speech output formats
- xAI text to speech