The new per-tenant TTS config surface diverged from the established TTS
schema after the audio refactor, dropping UI alias fields and root-level
settings during round-trip. It also returned ok=true even when non-secret
system config writes failed. This patch accepts backward-compatible field
aliases, round-trips timeout and Edge settings, reuses tenant timeout/rate
when building ephemeral providers, and returns errors on failed saves.
Constraint: Must preserve the existing TTS config schema expected by dashboard flows and legacy config docs
Rejected: Fix only the UI payload shape | backend would still break legacy aliases and direct API callers
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: When extending per-tenant config handlers, keep request/response structs aligned with the established config schema and do not ignore store write errors
Related: #935
Related: #936
Tested: go test ./internal/http -run 'Test(TTSConfig|TestConnection_)' -count=1 -v
Tested: go build ./...
Tested: go build -tags sqliteonly ./...
Not-tested: Full repo race test suite
- Add per-tenant TTS configuration endpoints (GET/POST /v1/tts/config)
with RoleAdmin auth instead of master scope
- Implement TenantTTSResolver for channels to use tenant-specific
TTS providers and auto mode settings
- Add per-agent voice override in channel TTS auto-apply:
- Extend OutboundMessage with AgentID and AgentOtherConfig
- Inject AgentAudioSnapshot in dispatch.go from outbound message
- MaybeApply reads tts_voice_id/tts_model_id from agent context
- Fix events.go to use RunContext.TenantID directly (H3)
- Fix dispatch.go error notification to use sendCtx (H1)
- Update UI to use new /v1/tts/config endpoints
- Add POST /v1/tts/test-connection for testing TTS credentials before saving
- Add UpdateManager() with RWMutex for thread-safe HTTP handler hot-reload
- Add sendVoice() for Telegram voice bubble support via audio_as_voice metadata
- Wire ttsHandler into gateway deps for config reload propagation