You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
stream synchronous TTS providers such as Edge sentence-by-sentence instead of waiting for the complete assistant reply
advertise the WebSocket audio encoding and decode encoded chunks sequentially in Desktop while preserving the existing raw PCM path
negotiate encoded-audio protocol v2 so older Desktop clients safely fall back instead of treating MP3 bytes as PCM
fall back to whole-text speech when synchronous synthesis fails before producing any audio
stop an encoded session cleanly on a decode error while draining audio already scheduled
wait for queued decoding/playback before settling the speech session, while retaining cancellation and fallback behavior
add a regression test proving the first synchronous-TTS sentence is emitted before the reply finishes
Why
Edge TTS produces encoded MP3 rather than native PCM. The previous fallback waited for the entire generated reply before synthesizing it, which created a long silent delay in voice conversation mode. This change provides application-level streaming without changing the behavior of providers that already support PCM streaming.
Related work
PR #74301 pipelines synthesis with local speaker playback in tools/tts_tool.py. This PR is complementary: it covers the Desktop WebSocket path in hermes_cli/web_server.py and encoded-audio decoding in the Electron renderer; the changed files and runtime paths do not overlap.
Thanks for addressing the synchronous-provider gap. Current main still closes /api/audio/speak-stream with fallback when no PCM streamer resolves (hermes_cli/web_server.py:4539), while the streaming-provider contract explicitly expects a per-sentence synchronous path for that case (tools/tts_streaming.py:196-199).
The PR adds that path at hermes_cli/web_server.py:4571-4596, preserves old-client behavior with the protocol-v2 gate at hermes_cli/web_server.py:4548-4554, and serializes encoded-clip decoding before draining at apps/desktop/src/lib/voice-playback.ts:272-299 and 342-365. The added backend tests cover early sentence emission and both pre- and post-audio failure behavior (tests/hermes_cli/test_web_server_speak_stream.py:94-156). No blocking issue identified from source review.
Vox Lockin lane 09 verification receipt — mergeable, no desktop-class gaps found.
Merge-clean against current main (70db671): no conflicts in apps/desktop/src/lib/voice-playback.ts or hermes_cli/web_server.py.
Desktop delta reviewed: protocol-v2 opt-in (audio_protocol=2) keeps old clients on the PCM path (no misinterpreting MP3 bytes as raw PCM), encoded sentence frames schedule through the existing nextStartAt queue, and decode failure falls back to whole-text playback. Consistent with the current hook's SpeechStreamSession contract (append/finish/done → 'fallback').
Tests: apps/desktop/src/lib/voice-playback.test.ts passes on PR head; the web-server speak-stream tests are outside the desktop lane but additive.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
area/streamingStreaming responses: gateway delivery, provider wirecomp/desktopElectron desktop app (apps/desktop/*)P3Low — cosmetic, nice to havesweeper:blast-moderateSweeper blast radius: moderate — a subsystem or single platformsweeper:risk-compatibilitySweeper risk: may break existing users, config, migrations, defaults, or upgradessweeper:risk-message-deliverySweeper risk: may drop, duplicate, misroute, or suppress messagestool/ttsText-to-speech and transcriptiontype/featureNew feature or request
4 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why
Edge TTS produces encoded MP3 rather than native PCM. The previous fallback waited for the entire generated reply before synthesizing it, which created a long silent delay in voice conversation mode. This change provides application-level streaming without changing the behavior of providers that already support PCM streaming.
Related work
PR #74301 pipelines synthesis with local speaker playback in
tools/tts_tool.py. This PR is complementary: it covers the Desktop WebSocket path inhermes_cli/web_server.pyand encoded-audio decoding in the Electron renderer; the changed files and runtime paths do not overlap.Testing
scripts/run_tests.sh tests/hermes_cli/test_web_server_speak_stream.py— 7 passednpm run test:ui -- src/lib/voice-playback.test.ts src/app/chat/composer/hooks/use-voice-conversation.test.tsx src/app/chat/composer/hooks/use-voice-conversation-rearm.test.tsx— 12 passednpm run typecheckvenv/bin/ruff check hermes_cli/web_server.py tests/hermes_cli/test_web_server_speak_stream.pynpx eslint src/lib/voice-playback.tsnpx prettier --check src/lib/voice-playback.tsnpm run buildnpm run builder -- --dir --macManual verification
fr-CA-SylvieNeuralstarts speaking before a long response finishes generating