#16569: feat(tts): add optional piper provider core support
stale
size: S
Cluster:
Text-to-Speech Provider Enhancements
## Summary
- Problem: Piper was not fully supported as a first-class TTS provider in core provider selection/config flow.
- Why it matters: Self-hosted users could not cleanly select/use Piper through standard TTS paths and provider
commands.
- What changed: Added core Piper provider support across TTS provider typing, config schema, provider selection/
status, and runtime synthesis path.
- What did NOT change (scope boundary): No language-aware routing in this PR (that is split to follow-up PR), no
docker-compose infra changes.
## Change Type (select all)
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [x] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [x] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Closes #
- Related #
## User-visible / Behavior Changes
- /tts provider piper is now supported.
- TTS provider status output includes Piper readiness (Piper URL: ✅/❌).
- Core config accepts messages.tts.piper with baseUrl, voice, timeoutMs.
- Telephony path explicitly keeps Piper unsupported (unchanged behavior for telephony capabilities).
- Piper endpoint is configurable: OpenClaw uses this precedence for base URL -> messages.tts.piper.baseUrl, then
PIPER_HTTP_URL, then fallback default http://piper-http:5001.
## Security Impact (required)
- New permissions/capabilities? (No)
- Secrets/tokens handling changed? (No)
- New/changed network calls? (Yes)
- Command/tool execution surface changed? (No)
- Data access scope changed? (No)
- If any Yes, explain risk + mitigation:
- Risk: New outbound HTTP call path to configured Piper endpoint.
- Mitigation: Endpoint is explicitly configured (messages.tts.piper.baseUrl or env fallback), request scope is
limited to TTS payload, existing timeout handling and error propagation are preserved.
## Repro + Verification
### Environment
- OS: macOS
- Runtime/container: local dev + Docker build validation during branch prep
- Model/provider: TTS provider selection flow
- Integration/channel (if any): TTS command path (/tts provider)
- Relevant config (redacted):
- messages.tts.provider: "piper"
- messages.tts.piper.baseUrl: "http://piper-http:5001"
### Steps
1. Set TTS provider to Piper via command or config.
2. Run provider status command (/tts provider) and inspect provider list/status.
3. Execute TTS flow and verify provider resolution includes Piper.
4. Run targeted TTS tests.
### Expected
- Piper accepted as a valid provider.
- Piper shown in provider status.
- Provider order/fallback logic includes Piper.
- TTS runtime can execute Piper path when configured.
### Actual
- Matches expected after this change.
## Evidence
Attach at least one:
- [x] Failing test/log before + passing after
- [ ] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)
## Human Verification (required)
- Verified scenarios:
- Added/updated tests in src/tts/tts.test.ts for Piper core provider behavior.
- Ran pnpm test -- src/tts/tts.test.ts (passing).
- Edge cases checked:
- Blank Piper base URL input normalizes to default Piper URL fallback.
- Piper marked unsupported in telephony path as intended.
- What you did not verify:
- Full production E2E across all messaging channels.
## Compatibility / Migration
- Backward compatible? (Yes)
- Config/env changes? (Optional)
- Migration needed? (No)
- If yes, exact upgrade steps:
- Optional: set messages.tts.provider: piper and messages.tts.piper.baseUrl.
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly:
- Switch provider back to openai/elevenlabs/edge, or revert this commit.
- Files/config to restore:
- src/auto-reply/reply/commands-tts.ts
- src/config/types.tts.ts
- src/config/zod-schema.core.ts
- src/tts/tts.ts
- src/tts/tts.test.ts
- Known bad symptoms reviewers should watch for:
- /tts provider piper not accepted.
- Piper incorrectly shown unavailable despite configured base URL.
## Risks and Mitigations
- Risk: Provider fallback order changes can alter which provider is attempted first when Piper is selected.
- Mitigation: Scoped tests verify provider ordering and configuration checks.
- Risk: Piper endpoint misconfiguration can cause failed synthesis attempts.
- Mitigation: Clear status output (Piper URL) and existing timeout/error handling in runtime path.
- Risk: default endpoint may not exist in every deployment.
- Mitigation: endpoint is explicitly overridable via config/env; default is only a fallback.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds Piper as a first-class TTS provider across the type system, config schema, provider selection/status commands, and the runtime synthesis path. The implementation follows existing provider patterns (type union, Zod schema, resolved config, provider order, `isTtsProviderConfigured`, and the `textToSpeech` loop).
- **Type & schema**: `TtsProvider` union, `TtsConfig`, Zod schema, and `ResolvedTtsConfig` all correctly extended with Piper fields (`baseUrl`, `voice`, `timeoutMs`).
- **Config resolution**: `resolveTtsConfig` resolves Piper base URL with a three-tier precedence (config → `PIPER_HTTP_URL` env → default `http://piper-http:5001`) and strips trailing slashes via `normalizeUrl`.
- **Provider commands**: `/tts provider` status and validation updated to include Piper; telephony path correctly skips Piper.
- **Temp directory leak**: The Piper synthesis path in `textToSpeech` does not clean up the temp directory when `piperTTS()` throws, unlike the Edge provider path which explicitly calls `rmSync`. This will leak temp directories on Piper failures.
- **Help text gap**: The `ttsUsage()` help text was not updated to list Piper as an available provider, so users won't discover it through `/tts help`.
<h3>Confidence Score: 3/5</h3>
- Functional but has a temp directory leak on Piper errors and a missing help text entry that should be fixed before merge.
- The core integration is well-structured and follows existing patterns. However, the temp directory leak in the Piper error path is a real resource issue (especially under repeated failures), and the missing help text is a user-facing oversight. Neither is critical/blocking, but both should be addressed.
- `src/tts/tts.ts` (temp directory leak in Piper error path), `src/auto-reply/reply/commands-tts.ts` (help text missing Piper)
<sub>Last reviewed commit: 486a8fa</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#16572: Feat/tts piper language routing
by akalypse · 2026-02-14
88.5%
#7965: feat(tts): add Speechify as TTS provider
by chaerla · 2026-02-03
76.6%
#22086: fix(tts): honor explicit config provider and model/voice settings
by AIflow-Labs · 2026-02-20
74.0%
#20794: feat(tts): add Fish Audio provider with full docs, tests & gateway ...
by twangodev · 2026-02-19
72.0%
#10870: feat(tts): add pocket-tts provider for local CPU-based TTS
by fayrose · 2026-02-07
70.5%
#7485: TTS: add Resemble AI provider support
by devshahofficial · 2026-02-02
70.1%
#21110: fix(tts): deliver audio via structured mediaUrl instead of MEDIA: t...
by hydro13 · 2026-02-19
70.0%
#8849: feat(tts): Add Chatterbox and Piper as first-class TTS providers
by emadomedher · 2026-02-04
69.3%
#19768: fix(security): OC-85 validate TTS provider directives against known...
by aether-ai-agent · 2026-02-18
68.6%
#8922: feat(voice-call): Add ElevenLabs WebSocket streaming TTS
by mikiships · 2026-02-04
68.4%