Add resilient TTS fallback and readiness status#806
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 25, 2026, 10:28 PM ET / 02:28 UTC. Summary Reproducibility: not applicable. as a bug reproduction because this is a feature/API PR. Source inspection confirms current main lacks Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Merge only after current-head live proof covers the runtime paths and maintainers explicitly accept the omitted-provider fallback plus Do we have a high-confidence way to reproduce the issue? Not applicable as a bug reproduction because this is a feature/API PR. Source inspection confirms current main lacks Is this the best way to solve the issue? Unclear pending maintainer product/API acceptance. The implementation is narrow and preserves explicit-provider strictness, but the fallback behavior, new command/result contract, and current-head proof should be accepted before merge. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c338d4111dc5. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
e14840d to
a6722a1
Compare
a639b16 to
6afed4f
Compare
6afed4f to
795eef1
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
795eef1 to
a9fc0c6
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
When the requested/configured TTS provider isn't usable (no ElevenLabs key, Piper voice not downloaded), gracefully fall back to Windows TTS instead of throwing, and report the effective vs requested provider plus a fellBack flag. A stale configured Windows voice now degrades to the system default voice so the fallback always speaks. Add a tts.status node command that reports per-provider readiness (ready/needs-api-key/needs-voice/voice-not-downloaded/unavailable) plus the configured/effective provider and willFallBack. PII-free. Wired across DangerousCommands gating, MCP descriptions, skill.md, and the setup allowlist export. Fix a stale pre-GA SHA-256 TODO docstring in PiperVoiceManager (verification is already implemented and enforced by AssetHashPinningTests). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Leave chat playback provider unset so TextToSpeechService can distinguish configured/default playback from explicit provider requests and apply the new Windows fallback when the configured provider is unavailable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a9fc0c6 to
60da376
Compare
Summary
Adds resilient text-to-speech provider handling for the Windows node.
tts.speaknow falls back to Windows TTS when the configured/default provider is not usable.tts.speakreportsrequestedProviderandfellBackso callers can explain degraded playback.tts.statuscommand that reports provider readiness without exposing voice IDs, API keys, device names, or exception details.tts.statusthrough capability registration, MCP docs,skill.md, setup-generated allowlists, and tests.Why
The Windows node already supports multiple TTS providers (
piper,windows,elevenlabs), but the previous behavior failed hard when the configured provider was not ready. Examples:Windows TTS is the reliable local fallback for configured/default provider degradation, so this change keeps speech working and makes provider state observable for callers. Explicit provider requests remain strict to preserve the existing provider-selection contract.
Behavior changes
tts.speakBefore:
{ spoken, provider, contentType, durationMs }.After:
piper, explicit unavailableelevenlabs, and unsupported provider IDs do not silently reroute to Windows.voiceId/modelwhen falling back so Windows does not reject a Piper/ElevenLabs voice ID.{ spoken, provider, requestedProvider, fellBack, contentType, durationMs }.tts.statusNew read-only command returning:
{ "configuredProvider": "piper", "effectiveProvider": "windows", "willFallBack": true, "providers": [ { "provider": "piper", "readiness": "voice-not-downloaded", "isReady": false }, { "provider": "windows", "readiness": "ready", "isReady": true }, { "provider": "elevenlabs", "readiness": "needs-api-key", "isReady": false } ] }Readiness values are fixed strings:
readyneeds-api-keyneeds-voicevoice-not-downloadedunavailableFiles of interest
src/OpenClaw.Shared/Capabilities/TtsCapability.cstts.status, provider-readiness types, fallback resolver, and expanded speak result.src/OpenClaw.Tray.WinUI/Services/TextToSpeech/TextToSpeechService.cssrc/OpenClaw.Tray.WinUI/Services/NodeService.csTtsCapability.StatusRequested.src/OpenClaw.Shared/Models.cstts.statusto privacy-gated command grouping.src/OpenClaw.Shared/Mcp/McpToolBridge.cstts.statusand updatedtts.speakresult shape.src/OpenClaw.WinNode.Cli/skill.mdsrc/OpenClaw.SetupEngine/SetupContext.cstts.statusin setup-generatedgateway.nodes.allowCommands.src/OpenClaw.Shared/Audio/PiperVoiceManager.cstests/...Proof
Validated locally on branch head
a9fc0c62, rebased onto currentorigin/main../build.ps1dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restoredotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restoredotnet test ./tests/OpenClaw.WinNode.Cli.Tests/OpenClaw.WinNode.Cli.Tests.csproj --no-restoredotnet test ./tests/OpenClaw.SetupEngine.Tests/OpenClaw.SetupEngine.Tests.csproj --no-restoreRuntime proof through the tray-local MCP path
I launched the actual Windows tray from this branch in an isolated data directory with:
elevenlabsThen I invoked the real local MCP endpoint through
winnode. This exercises:winnode→ local MCP HTTP server →NodeService→TtsCapability→TextToSpeechServiceTerminal output:
This confirms the registered runtime tool surface, readiness payload, configured/default fallback through
TextToSpeechService, and strict explicit-provider behavior.Additional verification:
main, is 0 commits behindorigin/main, and contains 1 commit / 11 files.UNSTABLEmeans CI is pending or has a non-merge failure, not a conflict).Current CI note
The current red
testjob is not caused by this TTS change. The job log shows:2026.6.9, npm latest2026.6.10; the workflow explicitly says to rungateway-lkg-updateto refresh the standing draft PR.WebSocketClientBaseTests.ReconnectBackoff_ReconnectsCurrentClosingSocket_WhenSupersededLoopIsActivefailed anAssert.TrueatWebSocketClientBaseTests.cs:411. This PR does not touch WebSocket client code, and the exact test passes locally as listed above.Notes / limits
tts.status.willFallBackreflects configured defaults. A specifictts.speakcall with its ownvoiceIdstays strict and may not match the default snapshot.tts.statusis grouped with the other voice commands behindNodeTtsEnabled.