← Back to PRs

#22186: feat(talk): add baseUrl support for custom TTS servers

by bautrey open 2026-02-20 21:06 View on GitHub →
app: android app: ios app: macos app: web-ui gateway extensions: talk-voice size: S
## Summary - Adds `baseUrl` field to the Talk Mode config, allowing users to point Talk Mode at any ElevenLabs-compatible TTS server instead of the hardcoded `https://api.elevenlabs.io` - When `baseUrl` is unset, all behavior is unchanged — clients default to ElevenLabs - Changes span all platforms: gateway TypeScript, macOS Swift, iOS Swift, Android Kotlin, and the talk-voice extension ## Motivation Local/self-hosted TTS servers that implement the ElevenLabs streaming API (e.g. [Sesame CSM-1B](https://github.com/bautrey/sesame-tts), Piper, Coqui) cannot be used with Talk Mode today because the API URL is hardcoded. This is the only thing blocking local TTS integration. The `ElevenLabsTTSClient` (from ElevenLabsKit) already accepts a `baseUrl` parameter — this PR just threads it through the config layer. ## Config example ```json { "talk": { "baseUrl": "http://localhost:8880", "voiceId": "conversationalB", "modelId": "csm1b", "outputFormat": "pcm_24000", "apiKey": "local" } } ``` ## Changes | File | Change | |------|--------| | `src/config/types.gateway.ts` | Add `baseUrl?: string` to `TalkConfig` type | | `src/gateway/protocol/schema/channels.ts` | Add `baseUrl` to `TalkConfigResultSchema` | | `src/gateway/server-methods/talk.ts` | Forward `baseUrl` in `normalizeTalkConfigSection` | | `extensions/talk-voice/index.ts` | Accept optional `baseUrl` in `listVoices()` | | `apps/macos/.../TalkModeRuntime.swift` | Parse `baseUrl`, pass to `ElevenLabsTTSClient` | | `apps/ios/.../TalkModeManager.swift` | Parse `baseUrl`, pass to `ElevenLabsTTSClient` | | `apps/android/.../TalkModeManager.kt` | Parse `baseUrl`, use in TTS + voice list URLs | ## Test plan - [ ] Verify Talk Mode works normally without `baseUrl` set (defaults to ElevenLabs) - [ ] Set `baseUrl` to a local ElevenLabs-compatible server and verify TTS streams correctly - [ ] Verify config reload picks up `baseUrl` changes without restart - [ ] Test on macOS, iOS, and Android 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> Added `baseUrl` support to Talk Mode configuration, allowing users to point TTS requests at custom ElevenLabs-compatible servers instead of the hardcoded ElevenLabs API. **Changes:** - Added optional `baseUrl` field to `TalkConfig` type and protocol schema - Updated gateway to forward `baseUrl` in config normalization - Modified all platform TTS clients (iOS, macOS, Android) to accept and use custom `baseUrl` - Updated `talk-voice` extension's `listVoices` function signature to accept `baseUrl` parameter **Issue found:** - The `talk-voice` extension's `/voice list` and `/voice set` commands don't pass the configured `baseUrl` to `listVoices()`, so they will always query the default ElevenLabs API instead of the custom server (lines 110, 119) <h3>Confidence Score: 3/5</h3> - Safe to merge after fixing the extension bug; otherwise TTS will work but voice management commands won't respect custom baseUrl - The implementation is mostly correct across all platforms (TypeScript, Swift, Kotlin), with proper config parsing, URL construction, and fallback handling. However, the extension has a logical bug where the `/voice` commands won't use the configured `baseUrl`, breaking the voice list/set functionality for custom TTS servers. This is a functional issue but not critical since core TTS streaming works correctly. - extensions/talk-voice/index.ts requires a fix to pass `baseUrl` from config to `listVoices()` calls <sub>Last reviewed commit: 9cd9562</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs