#22086: fix(tts): honor explicit config provider and model/voice settings
app: web-ui
gateway
size: M
Cluster:
Security Enhancements for TTS
## Summary
- Preserve explicit `messages.tts.provider` precedence over persisted runtime preferences in `getTtsProvider`.
- Keep existing behavior where runtime prefs are used only when no provider is explicitly configured in config.
- Add regression coverage for:
- config provider overriding persisted `/tts` provider preference
- OpenAI TTS request body using configured `model` and `voice`
## Why
Issue [#22005](https://github.com/openclaw/openclaw/issues/22005) reports explicit `messages.tts.openai.*` settings being ignored. A persisted TTS provider preference can out-prioritize explicit config, so explicit OpenAI config values were effectively bypassed.
## Validation
- `pnpm exec oxlint --type-aware src/tts/tts.ts src/tts/tts.test.ts`
- `pnpm exec oxfmt --check src/tts/tts.ts src/tts/tts.test.ts`
- `pnpm vitest run --config vitest.unit.config.ts src/tts/tts.test.ts`
Closes #22005
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed TTS config provider precedence to ensure explicit config settings override persisted runtime preferences. Also preserved approved device scopes across token rotations and kept UI chat draft text during abort operations.
Key changes:
- Reordered `getTtsProvider` logic to check `config.providerSource === "config"` before checking persisted `prefs.tts?.provider`
- Added `approvedScopes` field to `PairedDevice` type to track all scopes ever approved for a device
- Updated device pairing and token rotation to accumulate scopes into `approvedScopes` via `mergeScopes`
- Modified gateway message handler to use `approvedScopes` (if present) when validating reconnection attempts
- Removed `host.chatMessage = ""` from `handleAbortChat` to preserve typed draft text
- Added comprehensive test coverage for all three fixes
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are well-isolated, properly tested with comprehensive coverage (37 passing tests), and address specific bugs without introducing breaking changes. The TTS fix correctly reorders precedence checks, the device pairing changes safely add a new optional field while maintaining backward compatibility, and the UI change is a simple one-line removal that preserves expected behavior.
- No files require special attention
<sub>Last reviewed commit: be2a0e5</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#23071: fix(tts): make config auto=off a hard-disable that overrides user p...
by hydro13 · 2026-02-22
82.4%
#23291: fix(tts): respect config auto=off over user prefs override
by SidQin-cyber · 2026-02-22
80.9%
#6677: fix(tts): always load fresh config for voice selection
by Jinqiao · 2026-02-01
80.3%
#16089: fix(tts): clarify directive syntax in prompts and strip malformed tags
by kmixter · 2026-02-14
79.1%
#7965: feat(tts): add Speechify as TTS provider
by chaerla · 2026-02-03
78.5%
#19768: fix(security): OC-85 validate TTS provider directives against known...
by aether-ai-agent · 2026-02-18
78.5%
#20794: feat(tts): add Fish Audio provider with full docs, tests & gateway ...
by twangodev · 2026-02-19
76.1%
#22618: feat(tts): add OpenAI TTS speed parameter support
by useramuser · 2026-02-21
75.8%
#19073: feat(voice-call): streaming TTS, barge-in, silence filler, hangup, ...
by odrobnik · 2026-02-17
75.2%
#18957: fix(tts): replace deprecated ElevenLabs eleven_monolingual_v1 model
by BinHPdev · 2026-02-17
74.2%