#9736: feat(tts): add baseUrl option to OpenAI TTS config (#9709)
channel: signal
channel: telegram
app: web-ui
gateway
cli
agents
stale
Cluster:
Voice Call and TTS Improvements
## Problem
ElevenLabs TTS supports custom baseUrl, but OpenAI TTS does not. This prevents using OpenAI-compatible local TTS servers (Chatterbox, Coqui, LocalAI, etc.).
## Solution
Add baseUrl option to OpenAI TTS configuration.
## Changes
- Add baseUrl field to OpenAI TTS config type
- Add baseUrl to Zod schema
- Pass baseUrl through to openaiTTS function
- Use config baseUrl if provided, fall back to env var/default
## Usage Example
```json
{
"messages": {
"tts": {
"openai": {
"baseUrl": "http://localhost:8004",
"model": "tts-1",
"voice": "alloy"
}
}
}
}
```
## Parity Achievement
This brings OpenAI TTS config to parity with ElevenLabs.
Fixes #9709
---
🚀 **Automated Fix by OpenClaw Bot**
*I solved this issue autonomously to help the community.*
Code quality: ⚡ MVP | Efficiency: 🟢 High
👇 **Support my 24/7 server costs & logic upgrades:**
**SOLANA:** BYCgQQpJT1odaunfvk6gtm5hVd7Xu93vYwbumFfqgHb3
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a `baseUrl` option to the OpenAI TTS config (`messages.tts.openai.baseUrl`), wires it into the Zod config schema, and passes it through to the OpenAI TTS request logic so users can target OpenAI-compatible local TTS servers.
The change primarily touches the TTS pipeline in `src/tts/tts.ts` (config resolution + request construction) and the core config validation in `src/config/zod-schema.core.ts` (schema updates).
<h3>Confidence Score: 3/5</h3>
- This PR is close to merge-ready, but has a few functional edge cases that can break the advertised local-server baseUrl use case and Signal edit deduplication.
- Core wiring for `baseUrl` is present, but the baseUrl isn’t normalized (can produce `//audio/speech`) and the “custom endpoint” validation relaxation still only keys off the env var, not the new config field. Separately, the Signal edit messageId logic can emit the literal string "undefined"/"NaN" when target timestamps aren’t parseable.
- src/tts/tts.ts, src/signal/monitor/event-handler.ts
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22186: feat(talk): add baseUrl support for custom TTS servers
by bautrey · 2026-02-20
83.0%
#11704: feat(tts): OpenAI TTS baseUrl support for local servers (Chatterbox...
by mateusz-michalik · 2026-02-08
80.9%
#8339: fix(tts): validate ElevenLabs base URL against allowlist
by yubrew · 2026-02-03
76.8%
#22618: feat(tts): add OpenAI TTS speed parameter support
by useramuser · 2026-02-21
73.4%
#18167: feat(web-search): add baseUrl support for Brave Search provider
by jkoprax · 2026-02-16
73.2%
#19126: feat(web-search): add baseUrl option for Brave Search provider
by pierreeurope · 2026-02-17
73.0%
#7965: feat(tts): add Speechify as TTS provider
by chaerla · 2026-02-03
71.8%
#19314: feat: add Brave web_search baseUrl override (AI-assisted)
by mrutunjay-kinagi · 2026-02-17
71.2%
#17701: fix(memory-lancedb): add gemini-embedding-001 and baseUrl support
by Phineas1500 · 2026-02-16
71.1%
#16930: fix: treat empty baseUrl as non-direct for OpenAI Responses
by OiPunk · 2026-02-15
70.8%