fix(stt): resolve API keys from ~/.hermes/.env via get_env_value (#17140)
Widen #17163 to the sibling file tools/transcription_tools.py, which had the same class of bug. STT provider call sites and the _get_provider selection gate called os.getenv(...) directly and missed keys that only lived in ~/.hermes/.env. Same pattern as tts_tool.py: one guarded top-level import of get_env_value (falls back to os.getenv on ImportError), then every API-key and paired-base-URL lookup swapped over. Call sites migrated: - _transcribe_groq — GROQ_API_KEY - _transcribe_mistral — MISTRAL_API_KEY - _transcribe_xai — XAI_API_KEY, XAI_STT_BASE_URL - _get_provider — GROQ/MISTRAL/XAI_API_KEY in explicit + auto branches Module-level defaults (DEFAULT_STT_MODEL, GROQ_BASE_URL, etc.) stay on os.getenv — they're import-time constants, not runtime config, and the dotenv fallback would add no value there. New regression tests in tests/tools/test_transcription_dotenv_fallback.py (8 cases) mirror briandevans' TTS tests: per-provider dotenv-key forwarding, selection-gate dotenv visibility, and an end-to-end probe that patches hermes_cli.config.load_env to simulate ~/.hermes/.env carrying the key while os.environ does not.
This commit is contained in:
@@ -42,6 +42,12 @@ from tools.tool_backend_helpers import managed_nous_tools_enabled, resolve_opena
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from hermes_cli.config import get_env_value
|
||||
except ImportError:
|
||||
def get_env_value(name, default=None):
|
||||
return os.getenv(name, default)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Optional imports — graceful degradation
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -222,7 +228,7 @@ def _get_provider(stt_config: dict) -> str:
|
||||
return "none"
|
||||
|
||||
if provider == "groq":
|
||||
if _HAS_OPENAI and os.getenv("GROQ_API_KEY"):
|
||||
if _HAS_OPENAI and get_env_value("GROQ_API_KEY"):
|
||||
return "groq"
|
||||
logger.warning(
|
||||
"STT provider 'groq' configured but GROQ_API_KEY not set"
|
||||
@@ -238,7 +244,7 @@ def _get_provider(stt_config: dict) -> str:
|
||||
return "none"
|
||||
|
||||
if provider == "mistral":
|
||||
if _HAS_MISTRAL and os.getenv("MISTRAL_API_KEY"):
|
||||
if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"):
|
||||
return "mistral"
|
||||
logger.warning(
|
||||
"STT provider 'mistral' configured but mistralai package "
|
||||
@@ -247,7 +253,7 @@ def _get_provider(stt_config: dict) -> str:
|
||||
return "none"
|
||||
|
||||
if provider == "xai":
|
||||
if os.getenv("XAI_API_KEY"):
|
||||
if get_env_value("XAI_API_KEY"):
|
||||
return "xai"
|
||||
logger.warning(
|
||||
"STT provider 'xai' configured but XAI_API_KEY not set"
|
||||
@@ -262,16 +268,16 @@ def _get_provider(stt_config: dict) -> str:
|
||||
return "local"
|
||||
if _has_local_command():
|
||||
return "local_command"
|
||||
if _HAS_OPENAI and os.getenv("GROQ_API_KEY"):
|
||||
if _HAS_OPENAI and get_env_value("GROQ_API_KEY"):
|
||||
logger.info("No local STT available, using Groq Whisper API")
|
||||
return "groq"
|
||||
if _HAS_OPENAI and _has_openai_audio_backend():
|
||||
logger.info("No local STT available, using OpenAI Whisper API")
|
||||
return "openai"
|
||||
if _HAS_MISTRAL and os.getenv("MISTRAL_API_KEY"):
|
||||
if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"):
|
||||
logger.info("No local STT available, using Mistral Voxtral Transcribe API")
|
||||
return "mistral"
|
||||
if os.getenv("XAI_API_KEY"):
|
||||
if get_env_value("XAI_API_KEY"):
|
||||
logger.info("No local STT available, using xAI Grok STT API")
|
||||
return "xai"
|
||||
return "none"
|
||||
@@ -527,7 +533,7 @@ def _transcribe_local_command(file_path: str, model_name: str) -> Dict[str, Any]
|
||||
|
||||
def _transcribe_groq(file_path: str, model_name: str) -> Dict[str, Any]:
|
||||
"""Transcribe using Groq Whisper API (free tier available)."""
|
||||
api_key = os.getenv("GROQ_API_KEY")
|
||||
api_key = get_env_value("GROQ_API_KEY")
|
||||
if not api_key:
|
||||
return {"success": False, "transcript": "", "error": "GROQ_API_KEY not set"}
|
||||
|
||||
@@ -640,7 +646,7 @@ def _transcribe_mistral(file_path: str, model_name: str) -> Dict[str, Any]:
|
||||
Uses the ``mistralai`` Python SDK to call ``/v1/audio/transcriptions``.
|
||||
Requires ``MISTRAL_API_KEY`` environment variable.
|
||||
"""
|
||||
api_key = os.getenv("MISTRAL_API_KEY")
|
||||
api_key = get_env_value("MISTRAL_API_KEY")
|
||||
if not api_key:
|
||||
return {"success": False, "transcript": "", "error": "MISTRAL_API_KEY not set"}
|
||||
|
||||
@@ -680,7 +686,7 @@ def _transcribe_xai(file_path: str, model_name: str) -> Dict[str, Any]:
|
||||
Supports Inverse Text Normalization, diarization, and word-level timestamps.
|
||||
Requires ``XAI_API_KEY`` environment variable.
|
||||
"""
|
||||
api_key = os.getenv("XAI_API_KEY")
|
||||
api_key = get_env_value("XAI_API_KEY")
|
||||
if not api_key:
|
||||
return {"success": False, "transcript": "", "error": "XAI_API_KEY not set"}
|
||||
|
||||
@@ -688,7 +694,7 @@ def _transcribe_xai(file_path: str, model_name: str) -> Dict[str, Any]:
|
||||
xai_config = stt_config.get("xai", {})
|
||||
base_url = str(
|
||||
xai_config.get("base_url")
|
||||
or os.getenv("XAI_STT_BASE_URL")
|
||||
or get_env_value("XAI_STT_BASE_URL")
|
||||
or XAI_STT_BASE_URL
|
||||
).strip().rstrip("/")
|
||||
language = str(
|
||||
|
||||
Reference in New Issue
Block a user