Provider RESOLUTION ran an installer. `_detect_local_backend` called `_try_lazy_install_stt` -> `pm.ensure_import`, and the TTS requirement entries called the SDK importers, which install their extra on import. Both sit in status paths: `wake.status` fires on every desktop gateway-open, `/voice status` and `GET /api/audio/voice-config` resolve the same chain, and `check_tts_requirements` is the `text_to_speech` tool's `check_fn`, so it runs on every tool listing. The install is a whole-environment rebuild (a fresh generation, `--all-packages` over the enabled set) under the per-install lock, so a passive probe could hold a sibling profile's backend off its port for tens of seconds — the `hermes-setup` onboarding backend gave up at 40 s while an unrelated status probe's rebuild held the lock. Availability now reads state: `pm.extras.available` for the extra (pm owns the extra->anchor table, counts sys.modules fakes, and honours platform gates), `find_spec` for the rest. A provider whose SDK installs at first use still counts as READY when lazy installs are allowed and its own credential and platform gate permit — otherwise the tool would vanish from the schema for exactly the users that install serves. Synthesis keeps its on-demand install, and the lazy STT path now asks for `stt-whisper`, the extra carrying only faster-whisper. Validated: tests/tools/ for the TTS/STT suites (test_tts_mistral's importable-SDK contract included). A/B on HEAD: the two new files' non-guard tests fail there (3 + 1), pass here; the guard test that transcription still installs passes on both.
39 lines
1.6 KiB
Python
39 lines
1.6 KiB
Python
"""STT provider RESOLUTION never installs; transcription still does.
|
|
|
|
Regression: ``_detect_local_backend`` lazy-installed faster-whisper, and it sits in the provider
|
|
resolution chain every status surface uses — ``wake.status`` (fired on every desktop
|
|
gateway-open), ``/voice status`` and ``GET /api/audio/voice-config``. Each of those could start a
|
|
full dependency rebuild, holding the per-install lock long enough to keep a sibling profile's
|
|
backend off its port.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from tools import transcription_tools
|
|
|
|
|
|
@pytest.fixture
|
|
def no_faster_whisper(monkeypatch):
|
|
"""A machine without faster-whisper or a whisper CLI, recording install attempts."""
|
|
attempts: list[int] = []
|
|
monkeypatch.setattr(transcription_tools, "_HAS_FASTER_WHISPER", False)
|
|
monkeypatch.setattr(transcription_tools, "_has_local_command", lambda: False)
|
|
monkeypatch.setattr(transcription_tools, "_try_lazy_install_stt",
|
|
lambda: attempts.append(1) or False)
|
|
return transcription_tools, attempts
|
|
|
|
|
|
def test_resolution_reports_unavailable_without_installing(no_faster_whisper):
|
|
tools, attempts = no_faster_whisper
|
|
assert tools._detect_local_backend() is None
|
|
assert tools._resolve_explicit_local() == "none"
|
|
assert attempts == []
|
|
|
|
|
|
def test_transcription_is_what_installs(no_faster_whisper):
|
|
tools, attempts = no_faster_whisper
|
|
result = tools._transcribe_local("/tmp/absent.wav", "base")
|
|
assert attempts == [1], "the action path lost its on-demand install"
|
|
assert result["success"] is False
|
|
assert "faster-whisper not installed" in result["error"]
|