From eaa2dd6d09c56f98dbfa8ce5fc766a08dc6046ef Mon Sep 17 00:00:00 2001 From: Zehua Wang Date: Tue, 14 Jul 2026 12:28:53 -0400 Subject: [PATCH] fix(stt): check selected provider (not any) + plugin support PR review feedback: - Replace _has_any_command_stt_provider() with selected-provider check via _resolve_command_stt_provider_config() - Add _check_plugin_stt_provider() for plugin-registered backends - Add tests: selected command, unrelated command (should NOT pass), and plugin provider path --- tests/tools/test_voice_mode.py | 50 ++++++++++++++++++++++++++++++++++ tools/voice_mode.py | 19 +++++++++++-- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/tests/tools/test_voice_mode.py b/tests/tools/test_voice_mode.py index 87ccdb29705..4b86e2d7406 100644 --- a/tests/tools/test_voice_mode.py +++ b/tests/tools/test_voice_mode.py @@ -500,6 +500,56 @@ class TestCheckVoiceRequirements: assert result["stt_available"] is False assert "STT provider: MISSING" in result["details"] + def test_command_stt_provider_selected(self, monkeypatch): + """Catch-all branch fires for a selected command provider (not any provider).""" + monkeypatch.setattr("tools.voice_mode._audio_available", lambda: True) + monkeypatch.setattr("tools.voice_mode.detect_audio_environment", + lambda: {"available": True, "warnings": []}) + monkeypatch.setattr("tools.transcription_tools._get_provider", lambda cfg: "my-custom-stt") + monkeypatch.setattr("tools.transcription_tools._resolve_command_stt_provider_config", + lambda p, c: {"command": "whisper_cpp"} if p == "my-custom-stt" else None) + + from tools.voice_mode import check_voice_requirements + + result = check_voice_requirements() + assert result["available"] is True + assert result["stt_available"] is True + assert "STT provider: OK (command: my-custom-stt)" in result["details"] + + def test_unrelated_command_provider_not_confused(self, monkeypatch): + """Unrelated command provider does NOT make a different selected provider appear OK.""" + monkeypatch.setattr("tools.voice_mode._audio_available", lambda: True) + monkeypatch.setattr("tools.voice_mode.detect_audio_environment", + lambda: {"available": True, "warnings": []}) + monkeypatch.setattr("tools.transcription_tools._get_provider", lambda cfg: "none") + monkeypatch.setattr("tools.transcription_tools._resolve_command_stt_provider_config", + lambda p, c: {"command": "whisper_cpp"} if p == "my-custom-stt" else None) + + from tools.voice_mode import check_voice_requirements + + result = check_voice_requirements() + assert result["available"] is False + assert result["stt_available"] is False + assert "STT provider: MISSING" in result["details"] + + def test_plugin_stt_provider(self, monkeypatch): + """Plugin STT provider is recognized.""" + monkeypatch.setattr("tools.voice_mode._audio_available", lambda: True) + monkeypatch.setattr("tools.voice_mode.detect_audio_environment", + lambda: {"available": True, "warnings": []}) + monkeypatch.setattr("tools.transcription_tools._get_provider", lambda cfg: "my-plugin-stt") + monkeypatch.setattr("tools.transcription_tools._resolve_command_stt_provider_config", + lambda p, c: None) + monkeypatch.setattr("tools.voice_mode._check_plugin_stt_provider", + lambda p: p == "my-plugin-stt") + + from tools.voice_mode import check_voice_requirements + + result = check_voice_requirements() + assert result["available"] is True + assert result["stt_available"] is True + assert "STT provider: OK (plugin: my-plugin-stt)" in result["details"] + # ============================================================================ # AudioRecorder diff --git a/tools/voice_mode.py b/tools/voice_mode.py index 822eb6f35cd..724aaa329a1 100644 --- a/tools/voice_mode.py +++ b/tools/voice_mode.py @@ -1269,6 +1269,17 @@ def listen_for_speech( # ============================================================================ # Requirements check # ============================================================================ +def _check_plugin_stt_provider(provider: str) -> bool: + """Return True when *provider* is backed by a registered TranscriptionProvider plugin.""" + if not provider: + return False + try: + from agent.transcription_registry import get_provider + return get_provider(provider.lower().strip()) is not None + except ImportError: + return False + + def check_voice_requirements() -> Dict[str, Any]: """Check if all voice mode requirements are met. @@ -1277,7 +1288,7 @@ def check_voice_requirements() -> Dict[str, Any]: ``missing_packages``, and ``details``. """ # Determine STT provider availability - from tools.transcription_tools import _get_provider, _has_any_command_stt_provider, _load_stt_config, is_stt_enabled + from tools.transcription_tools import _get_provider, _load_stt_config, _resolve_command_stt_provider_config, is_stt_enabled stt_config = _load_stt_config() stt_enabled = is_stt_enabled(stt_config) stt_provider = _get_provider(stt_config) @@ -1319,8 +1330,10 @@ def check_voice_requirements() -> Dict[str, Any]: details_parts.append("STT provider: OK (xAI Grok STT)") elif stt_provider == "elevenlabs": details_parts.append("STT provider: OK (ElevenLabs Scribe)") - elif _has_any_command_stt_provider(stt_config): - details_parts.append(f"STT provider: OK ({stt_provider})") + elif _resolve_command_stt_provider_config(stt_provider, stt_config): + details_parts.append(f"STT provider: OK (command: {stt_provider})") + elif _check_plugin_stt_provider(stt_provider): + details_parts.append(f"STT provider: OK (plugin: {stt_provider})") else: details_parts.append( "STT provider: MISSING (uv pip install faster-whisper — "