From d3e07bdaaaeb6eae43544745decf3449c0cd5326 Mon Sep 17 00:00:00 2001 From: Damian Kluk Date: Sun, 14 Jun 2026 12:12:39 +0000 Subject: [PATCH] fix(stt): better error logging and smarter DM when STT install fails Three improvements to the voice-transcription setup flow: 1. tools/transcription_tools.py - Log lazy-install failures at WARNING instead of DEBUG, and include actionable guidance about venv permission issues (the most common cause of silent STT failures). 2. gateway/run.py - Smart DM message: check the actual stt config before sending setup instructions. If stt.enabled is already true and provider is 'local', skip the redundant 'set stt.enabled' advice and show a permission-aware install hint instead. 3. gateway/run.py - Agent note now includes a config-aware hint about why STT is unavailable (e.g. 'provider is local but faster-whisper failed to install'). --- gateway/run.py | 75 +++++++++++++++++++++++++++++++----- tools/transcription_tools.py | 14 ++++++- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/gateway/run.py b/gateway/run.py index a388f184ad6..bd0b6e3006f 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -8616,15 +8616,50 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew _stt_meta = self._thread_metadata_for_source(source, self._reply_anchor_for_event(event)) if _stt_adapter: try: - _stt_msg = ( + # Build a smarter DM — check what the user has already configured + _stt_msg_parts = [ "🎤 I received your voice message but can't transcribe it — " - "no speech-to-text provider is configured.\n\n" - "To enable voice: install faster-whisper " - "(`uv pip install faster-whisper` in the Hermes venv; " - "`pip install faster-whisper` also works if pip is on PATH) " - "and set `stt.enabled: true` in config.yaml, " - "then /restart the gateway." - ) + "no speech-to-text provider is available." + ] + try: + from tools.transcription_tools import _load_stt_config, is_stt_enabled + _cfg = _load_stt_config() + _enabled = is_stt_enabled(_cfg) + _provider = _cfg.get("provider", "auto") + if not _enabled: + _stt_msg_parts.append( + "✅ **STT is disabled** in your config " + "(`stt.enabled: false`). Set it to `true` " + "and /restart the gateway." + ) + elif _provider in ("local", "auto"): + _stt_msg_parts.append( + "To enable local voice transcription:\n" + "1. Install faster-whisper:\n" + " `VIRTUAL_ENV=/opt/hermes/.venv uv pip install \"faster-whisper==1.2.1\"`\n" + "2. If you get a **permission denied** error, the venv is owned by " + "a different user. Run the install command as the venv owner:\n" + " `su - $(stat -c '%U' /opt/hermes/.venv) -c 'VIRTUAL_ENV=/opt/hermes/.venv " + "uv pip install \"faster-whisper==1.2.1\"'`\n" + "3. Then /restart the gateway." + ) + else: + # Cloud provider — API key may be missing + _stt_msg_parts.append( + f"Your configured STT provider is **{_provider}**. " + "Make sure the required API key is set in your `.env` file, " + "then /restart the gateway." + ) + except Exception: + # Fallback if the config check itself fails + _stt_msg_parts.append( + "To enable voice: install faster-whisper " + "(`uv pip install faster-whisper` in the Hermes venv; " + "`pip install faster-whisper` also works if pip is on PATH) " + "and set `stt.enabled: true` in config.yaml, " + "then /restart the gateway." + ) + _stt_msg = "\n\n".join(_stt_msg_parts) if self._has_setup_skill(): _stt_msg += "\n\nFor full setup instructions, type: `/skill hermes-agent-setup`" await _stt_adapter.send( @@ -12876,9 +12911,31 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew "No STT provider" in error or error.startswith("Neither VOICE_TOOLS_OPENAI_KEY nor OPENAI_API_KEY is set") ): + # Check if STT is actually configured — helps the agent + # give a better response than the generic "not configured". + _stt_config_hint = "" + try: + from tools.transcription_tools import _load_stt_config, is_stt_enabled + _cfg = _load_stt_config() + if is_stt_enabled(_cfg): + _provider = _cfg.get("provider", "auto") + if _provider == "local": + _stt_config_hint = ( + " (Note: stt.enabled is true and provider is 'local', " + "but faster-whisper failed to install — likely a venv " + "write-permission issue)" + ) + else: + _stt_config_hint = ( + f" (Note: stt.enabled is true, provider is '{_provider}', " + "but the provider is unavailable)" + ) + except Exception: + pass _no_stt_note = ( "[The user sent a voice message but I can't listen " - "to it right now — no STT provider is configured. " + "to it right now — no STT provider is available." + f"{_stt_config_hint} " "A direct message has already been sent to the user " "with setup instructions." ) diff --git a/tools/transcription_tools.py b/tools/transcription_tools.py index d0712c81e1e..b8fcd509d36 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -223,8 +223,20 @@ def _try_lazy_install_stt() -> bool: import importlib.util as _iu if _iu.find_spec("faster_whisper"): return True + logger.warning( + "faster-whisper was installed but importlib still cannot find it " + "(may require Python restart)" + ) except Exception as exc: - logger.debug("Lazy install of faster-whisper failed: %s", exc) + logger.warning( + "Lazy install of faster-whisper failed: %s. " + "This is often a permission issue: the Hermes process user cannot " + "write to the virtual environment. Try running manually as the " + "venv owner: `stat -c '%%u' '$(dirname $(dirname $(which python3)))'` " + "then `su - -c 'VIRTUAL_ENV=/opt/hermes/.venv " + "uv pip install faster-whisper==1.2.1'`", + exc, + ) return False