fix(tts): piper lazy-install parity + probe install-safety + null-config guards - #78202
fix(tts): piper lazy-install parity + probe install-safety + null-config guards#78202andrexibiza wants to merge 6 commits into
Conversation
|
CI on this PR failed on Evidence:
Fix: the test is stabilized in #78221 (immediate first tick, 250ms idle window, 5× tick period — pass still depends on the progress extension). Once #78221 merges and this branch picks up main, this slice should go green. No code change needed on this PR. |
|
Checks on this PR were red on Verification on the new head (3 consecutive local runs): Note for merge ordering: the same test fix exists on #78221 — when both merge, git will dedupe (identical change); either merge order is fine. |
|
The re-run after the This is a sporadic load-timing flake, not a change from this PR:
Treating this as evidence-documented and separate from the PR's scope; the compression-isolation test hardening would be its own change if it keeps flaking. |
758ffa3 to
da85ac2
Compare
The built-in piper TTS provider had no entry in tools/lazy_deps.py
LAZY_DEPS, so selecting it on a fresh install fails with a hard error
instead of auto-installing like edge/elevenlabs/mistral providers.
Changes:
- Add "tts.piper": ("piper-tts==1.4.2",) to LAZY_DEPS
- Update _import_piper() to call ensure("tts.piper") before importing,
matching the pattern used by _import_edge_tts() and _import_elevenlabs()
- Add regression tests for feature registration, ensure() call, and
_check_piper_available()
Fixes NousResearch#44001
(cherry picked from commit fc4f17b)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
_get_provider resolved an uninstalled explicit 'local' STT provider by running a synchronous lazy pip install (lazy_deps.ensure -> uv pip install faster-whisper, up to 300s). The TUI's wake.start startup handshake calls check_wake_word_requirements() -> _stt_ready() -> _get_provider(), so on a box with stt.provider=local and faster-whisper missing, the handshake froze for the length of the pip install and the UI sat on 'forging session...' until the install timed out or was killed. Mirror the existing _tts_ready 'PROBE, not an installer' fix (the TTS path already shipped this guard): add an install switch to _get_provider (default True, backward compatible), pass install=False from the wake-word and voice requirements probes, and treat an uninstalled-but-installable local provider as ready -- it installs lazily at first real transcription. check_voice_requirements had the same freeze via the TUI's voice.toggle status RPC and is fixed in the same pass. Regression test mirrors test_tts_ready_is_a_probe_never_an_installer. (cherry picked from commit d43be77) Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
Completes the provider-registry / lazy-install class on top of the salvaged commits (authorship preserved from NousResearch#44010 / NousResearch#77040): - Align piper-tts pins across all three install surfaces: the new [piper] extra in pyproject.toml, the tts.piper LAZY_DEPS entry, and the hermes tools post-setup installer (previously unpinned '-U piper-tts' could drift from the lazy pin and force a downgrade on first use). Regenerated uv.lock (adds piper-tts + pathvalidate). - Update the lazy-covered-extras contract in test_project_metadata.py so [piper] can never leak back into [all]. - Make test_piper_lazy_install.py environment-independent (mock find_spec instead of assuming piper is absent) and assert the lazy pin matches the pyproject extra. - check_voice_requirements: explicit uninstalled 'local' STT counts as ready when lazy installs are permitted, so classic '/voice on' can still activate and install at first transcription — without the probe itself ever running pip. - wake_word._stt_ready: restrict the lazy-install readiness exception to 'local' only; local_command is never lazy-installed by the resolver, so arming the wake word on it would be unbacked. - tts_tool._generate_kittentts: null-coalesce the kittentts subsection read for parity with the NousResearch#47318 null-config crash-proofing already on main. Tests: test_tts_registry, test_plugins_tts_registration, test_tts_container_repair, test_piper_lazy_install, test_wake_word, test_voice_mode (minus pre-existing Windows env failures), test_packaging_metadata, test_project_metadata, test_lazy_deps, test_tts_piper, test_tts_plugin_dispatch. Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
The stderr-progress idle-timeout test used a 0.1s idle window with 0.04s ticks — shorter than Windows process spawn, so the first chunk could never arrive in time (deterministic failure on Windows, flake under Linux CI load). Verified failing identically on pristine main before the change. Fix: emit the first tick immediately, tick every 50ms for ~400ms total, 250ms idle window (5x tick period). The pass still depends on the progress extension while tolerating real spawn/scheduling latency. Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…er CI load test_f3_mutating_engine_cannot_touch_live_transcript_after_timeout used 30s/5s thread-wait budgets that scheduler starvation under 8-worker CI exceeds, failing the isolation assertions vacuously. The worker must stay blocked for the host to run its byte-identity checks; 300s/60s budgets preserve every assertion while tolerating load. Fixes the slice-8/8 flake that blocks unrelated PRs (observed on NousResearch#78202 CI: 3632 passed, 1 flaked). Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…it release Pins the NousResearch#76354 F3 flake class: the worker must block on the release EVENT, never a wall-clock budget, so scheduler starvation cannot let it exit and run the isolation assertions vacuously. The test proves the worker is still alive after the host's full byte-identity assertion pass and completes only after release_engine is set. Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
da745ea to
f8716db
Compare
Related #44001 #44010 #47318 #61799 #77040 #77932
What changed and why
This PR completes the provider registry & lazy-install consistency bug class: built-in providers must be lazy-installable on fresh installs, requirements probes must never trigger pip installs, and provider fallback/readiness reporting must be truthful. It salvages and completes two open PRs (authorship preserved, see credits) plus the remaining null-config gap.
1. Piper TTS is now lazy-installable (issue #44001)
tools/lazy_deps.py: added the missingtts.piperfeature entry (was absent — fresh installs withtts.provider: piperfailed with a manual-install error while edge/elevenlabs/mistral auto-installed).tools/tts_tool.py::_import_piper: callslazy_deps.ensure("tts.piper")before importing, matching the Edge/ElevenLabs/Mistral pattern.piper-tts==1.4.2is now pinned in all three places — the new[piper]extra inpyproject.toml, thetts.piperlazy entry, and thehermes toolspost-setup installer (previously unpinned-U piper-tts, which could install a newer version and then get downgraded by the lazy pin on first use).uv.lockregenerated (addspiper-tts+pathvalidate).tests/test_project_metadata.py:[piper]added to the lazy-covered-extras contract so it can't leak into[all].tests/tools/test_piper_lazy_install.py: environment-independent (mocksfind_specinstead of assuming piper is absent) and asserts the lazy pin matches the pyproject extra.2. Requirements probes never lazy-install (follow-up to #77040)
tools/transcription_tools.py::_get_provider: newinstall: bool = Truekwarg; probe callers passinstall=Falseso a bare status check can never freeze on a pip install.tools/voice_mode.py::check_voice_requirementsandtools/wake_word.py::_stt_readycall it withinstall=False.localSTT provider now counts as ready when lazy installs are permitted — so classic/voice onstill activates and the install happens at first real transcription, instead of rejecting an installable provider before the transcription path could install it. The probe itself never runs pip (regression test assertsinstall=Falseis passed).local_commandexception removed (maintainer-flagged gap): the wake probe previously treated explicitlocal_commandas ready whenever lazy installs were allowed, but the resolver never lazy-installs faster-whisper forlocal_command— arming the wake word on it would be unbacked. The readiness exception is now restricted tolocalonly, with a regression test.3. Null-config crash-proofing parity (issue #47318)
tools/tts_tool.py::_generate_kittentts: thekittenttssubsection read was the last TTS provider section not null-coalesced (tts.kittentts: nullin config.yaml would yieldNone). Now uses the(x or {})pattern already applied everywhere else on main (the core local: null / edge: null in config.yaml crashes STT/TTS with 'NoneType' object has no attribute 'get' #47318 fix landed earlier via fix(stt/tts): null provider subsections no longer crash voice tools (#47318) #61799; this closes the remaining site).How to test
Behavioral probes run during development:
tools.lazy_deps.LAZY_DEPS["tts.piper"]exists;_import_piper()callsensure("tts.piper", prompt=False)._get_provider({"enabled": True, "provider": "local", ...}, install=False)makes 0 calls to_try_lazy_install_stt, whileinstall=Truemakes exactly 1.provider: "edge"+fallback_from: "missing-provider"instead of masquerading as the unknown name.stt.local: null/tts.edge: null/tts.kittentts: nullloads and both TTS generation and STT provider resolution complete without'NoneType' object has no attribute 'get'.Platforms tested
git diff origin/main --checkclean;scripts/check-windows-footguns.pyclean on all touched files (only pre-existing WSL-gated test line flagged, not touched by this PR).Why this matters to users
pip install piper-tts— it now auto-installs on first use like every other built-in provider, at a version consistent withhermes tools(no surprise downgrades)./voice on,wake.status, and TUI status polls never hang on pip installs — but an installable local STT provider still activates correctly and installs at first transcription.fallback_from), so agents/users aren't silently misled about which engine produced the audio.Fixes #44001
Credits
fdccbd6431.f576f7b907.[piper]extra + lockfile, activation-gate preservation,local_commandexception removal, null-coalesce for kittentts, tests) by @andrexibiza — commite35c25ff69.Part of #65160
Part of #78207
Part of #79890