fix(engine): initialize timed_out before empty-reply check and move credit to Highlights (#2103)

This commit is contained in:
LMGXENON
2026-09-15 00:43:25 +01:00
parent 750aa2eb57
commit 50cba2881c
3 changed files with 25 additions and 2 deletions
+1 -2
View File
@@ -11,7 +11,7 @@ the frozen-backend fallback mirror it for their toolchains.
**Highlights**
- Electron now ships as a complete cross-platform VoiceStudio desktop app with local-first cloning, production workspaces, model packs, repair agents, native integrations, updates, parity checks, and the shared backend contracts required by those workflows (#1823)
- Subprocess and ASR sidecars report their receive timeout when killed by deadline instead of describing a pipe-closed crash, and four engines raise their sidecar watchdog from 60s (#2103) — thanks @LMGXENON!
- The Model Catalogue is one page: what you use now on top, then each family's engines and weights (#2013)
- VoxCPM2 installs in one click into its own environment, with the CUDA build of PyTorch on NVIDIA GPUs (#2021)
- MOSS-TTS-Nano installs in one click into its own environment, pinned to a reviewed upstream commit it works with (#2022)
@@ -25,7 +25,6 @@ the frozen-backend fallback mirror it for their toolchains.
### Fixed
- Subprocess and ASR sidecars report their receive timeout when killed by deadline instead of describing a pipe-closed crash, and four engines raise their sidecar watchdog from 60s (#2103) — thanks @LMGXENON!
- Stopping a process on macOS no longer fails with "Operation not permitted" when it was already exiting (#2032)
- A YouTube link blocked by its "not a bot" check now says how to attach signed-in cookies in Dub, instead of quoting yt-dlp's command-line flags (#2036, #2034)
- An engine that fails to start now says whether it timed out, crashed (with its exit code and last output) or answered wrongly, instead of "did not signal ready: None" (#2037, #2026)
+1
View File
@@ -760,6 +760,7 @@ class SubprocessBackend(TTSBackend):
try:
self._send(msg)
reply = self._recv_with_timeout(self.recv_timeout_s)
timed_out = self._last_recv_timed_out
except (RuntimeError, OSError):
# A broken or malformed protocol stream cannot be reused.
# Reap it before releasing the request lock so an immediate
@@ -439,6 +439,29 @@ def test_subprocess_sidecar_timeout_error_message(monkeypatch):
assert "killed mid-generate" in str(exc.value)
def test_subprocess_sidecar_initial_empty_crash_reports_pipe_closed(monkeypatch):
"""When a sidecar process terminates without timing out, generate() reports pipe closure (#2103)."""
b = _PlainBackend()
class _FakeProc:
def poll(self):
return None
b._proc = _FakeProc()
monkeypatch.setattr(b, "_send", lambda msg: None)
def fake_recv_crash(timeout_s):
b._last_recv_timed_out = False
return None
monkeypatch.setattr(b, "_recv_with_timeout", fake_recv_crash)
monkeypatch.setattr(b, "_reap_unusable_process", lambda proc: None)
with pytest.raises(RuntimeError) as exc:
b.generate("hello")
assert "sidecar closed pipe mid-generate" in str(exc.value)
def test_subprocess_engine_timeouts_raised():
"""All large subprocess TTS engines must declare generous timeouts rather
than inheriting the 60s class default (#2103)."""