LibreChat/client
Danny Avila 36f129089b
🔊 fix: Autoplay Latest Message for Browser TTS and short responses (#15347)
* 🔊 fix: Autoplay Latest Message for Browser TTS and short responses

Automatic playback never reached the Web Speech API and dropped audio for
short responses. Two independent defects:

Autoplay ignored the selected TTS engine. `ChatForm` mounted `StreamAudio`
whenever automatic playback was on, and that component always POSTs to
`/api/files/speech/tts`, so the Browser engine silently fell through to the
external endpoint and `speechSynthesis.speak()` was never called. The
engine-aware `useTextToSpeech` hook had no consumers. Autoplay now selects
its driver by engine the same way `MessageAudio` does, with the gate shared
between both drivers so they trigger on identical terms.

`MediaSourceAppender` stranded its queue. `tryAppendNextChunk` only ran from
`addData` and `updateend`, while `sourceopen` — which fires only once a media
element attaches the object URL — created the `SourceBuffer` without draining
what had queued up behind it. A response read in full before that event left
every chunk in the queue with no `updateend` to ever restart the drain, so the
element sat at `readyState: 0` and never played. Short responses lost the race;
longer ones streamed past `sourceopen` and worked. The handler now drains, and
`close()` (previously never called) ends the stream once the queue empties.

Also in the same path: the error branch had its timeout comparison inverted, so
real failures were logged as timeouts and swallowed; and the non-MSE fallback
that hands the element a finished blob lived inside the cache-only branch,
leaving browsers without MSE support for `audio/mpeg` with no audio at all
unless Cache TTS happened to be enabled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0184N7d9kgpdqmbCb9ujMmNX

* 🧹 style: Sort imports in autoplay files

`npm run sort-imports:check` on the changed files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0184N7d9kgpdqmbCb9ujMmNX

* 🔇 fix: End the media source when no audio ever arrives

Codex P2 on #15347. The `hasAppended` guard in `tryEndOfStream` was defensive
against a throw that cannot happen: `endOfStream()` only raises
`InvalidStateError` while the source is not open or a buffer is updating, both
of which the remaining guards already cover. Nothing about an empty buffer
throws.

The guard's actual effect was to strand the two cases it was meant to protect.
A TTS response that completes with zero bytes, or a read timeout that fires
before the first byte, both reach `close()` with the MediaSource URL already
attached to the element — and left it `open` forever, so the element waited on
a source that could never receive data and kept its streaming resources
2026-08-30 06:54:16 -04:00
..
public 🪢 feat: Langfuse Fanout Connection Setting (#14108) 2026-07-29 18:33:10 -04:00
scripts
src 🔊 fix: Autoplay Latest Message for Browser TTS and short responses (#15347) 2026-08-30 06:54:16 -04:00
sw
test 🔒 chore: Upgrade react-router-dom to v7.18.2 (security) (#14582) 2026-08-01 17:19:52 -04:00
babel.config.cjs
check_updates.sh
index.html 📡 feat: add rum browser page-load diagnostics (#14106) 2026-07-05 11:32:53 -04:00
jest.config.cjs 🧮 fix: Currency-Safe Single-Dollar LaTeX via Micromark Tokenizer (#15181) 2026-08-24 22:29:02 -04:00
jest.resolver.cjs ⬆️ chore: Migrate off deprecated @ariakit/react-core to @ariakit/react-components (#13940) 2026-06-24 23:13:57 -04:00
nginx.conf 🐳 feat: Bundle Admin Panel in Docker Compose Stacks (#13876) 2026-06-22 16:59:08 -04:00
package.json 🧮 fix: Currency-Safe Single-Dollar LaTeX via Micromark Tokenizer (#15181) 2026-08-24 22:29:02 -04:00
postcss.config.cjs
tailwind.config.cjs feat: Context Gauge Hover Reveal and Breakdown Motion Polish (#15038) 2026-08-21 11:34:36 -04:00
tsconfig.json
vite.config.ts 🎨 refactor: adopt the @librechat/client design system (semantic color tokens + component migration) (#13879) 2026-08-06 09:15:17 -04:00