mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(tools): resolve TTS/STT provider keys through credential pool
TTS/STT providers (Mistral, ElevenLabs) only checked env vars and .env files via get_env_value(), ignoring keys stored via 'hermes auth add mistral' / 'hermes auth add elevenlabs'. Add _resolve_provider_key() helper that falls back to the credential pool (agent.credential_pool.load_pool) when the env var is unset. Affected: - tools/transcription_tools.py: 6 sites (provider selection + auto-detect) - tools/tts_tool.py: 6 sites (synthesis + availability check) Fixes #68003
This commit is contained in:
parent
ed591a5664
commit
79bcfc23ab
2 changed files with 59 additions and 11 deletions
|
|
@ -62,6 +62,30 @@ def get_env_value(name, default=None):
|
|||
value = _get_env_value(name)
|
||||
return default if value is None else value
|
||||
|
||||
|
||||
def _resolve_provider_key(env_var: str, provider_id: str) -> str:
|
||||
"""Resolve an API key from env, .env, or the credential pool.
|
||||
|
||||
Used by TTS/STT providers (Mistral, ElevenLabs) that store keys
|
||||
via ``hermes auth add <provider_id>``.
|
||||
"""
|
||||
key = get_env_value(env_var)
|
||||
if key:
|
||||
return key
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
pool = load_pool(provider_id)
|
||||
if pool and pool.has_credentials():
|
||||
entry = pool.peek()
|
||||
if entry:
|
||||
key = getattr(entry, "access_token", "") or getattr(entry, "runtime_api_key", "")
|
||||
key = str(key).strip()
|
||||
if key:
|
||||
return key
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Optional imports — graceful degradation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -843,7 +867,7 @@ def _get_provider(stt_config: dict) -> str:
|
|||
return "none"
|
||||
|
||||
if provider == "mistral":
|
||||
if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"):
|
||||
if _HAS_MISTRAL and _resolve_provider_key("MISTRAL_API_KEY", "mistral"):
|
||||
return "mistral"
|
||||
logger.warning(
|
||||
"STT provider 'mistral' configured but mistralai package "
|
||||
|
|
@ -862,7 +886,7 @@ def _get_provider(stt_config: dict) -> str:
|
|||
return "none"
|
||||
|
||||
if provider == "elevenlabs":
|
||||
if get_env_value("ELEVENLABS_API_KEY"):
|
||||
if _resolve_provider_key("ELEVENLABS_API_KEY", "elevenlabs"):
|
||||
return "elevenlabs"
|
||||
logger.warning(
|
||||
"STT provider 'elevenlabs' configured but ELEVENLABS_API_KEY not set"
|
||||
|
|
@ -904,7 +928,7 @@ def _get_provider(stt_config: dict) -> str:
|
|||
# Only auto-select Mistral if the SDK is already present — don't trigger a
|
||||
# lazy-install during passive auto-detection. Explicit `provider: mistral`
|
||||
# (above) does lazy-install on first transcription call.
|
||||
if _HAS_MISTRAL and get_env_value("MISTRAL_API_KEY"):
|
||||
if _HAS_MISTRAL and _resolve_provider_key("MISTRAL_API_KEY", "mistral"):
|
||||
logger.info("No local STT available, using Mistral Voxtral Transcribe API")
|
||||
return "mistral"
|
||||
try:
|
||||
|
|
@ -915,7 +939,7 @@ def _get_provider(stt_config: dict) -> str:
|
|||
return "xai"
|
||||
except Exception:
|
||||
pass
|
||||
if get_env_value("ELEVENLABS_API_KEY"):
|
||||
if _resolve_provider_key("ELEVENLABS_API_KEY", "elevenlabs"):
|
||||
logger.info("No local STT available, using ElevenLabs Scribe STT API")
|
||||
return "elevenlabs"
|
||||
if _HAS_OPENAI and (get_env_value("DEEPINFRA_API_KEY") or "").strip():
|
||||
|
|
@ -1483,7 +1507,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 = get_env_value("MISTRAL_API_KEY")
|
||||
api_key = _resolve_provider_key("MISTRAL_API_KEY", "mistral")
|
||||
if not api_key:
|
||||
return {"success": False, "transcript": "", "error": "MISTRAL_API_KEY not set"}
|
||||
|
||||
|
|
@ -1632,7 +1656,7 @@ def _transcribe_xai(file_path: str, model_name: str) -> Dict[str, Any]:
|
|||
|
||||
def _transcribe_elevenlabs(file_path: str, model_name: str) -> Dict[str, Any]:
|
||||
"""Transcribe using ElevenLabs Scribe STT API."""
|
||||
api_key = get_env_value("ELEVENLABS_API_KEY")
|
||||
api_key = _resolve_provider_key("ELEVENLABS_API_KEY", "elevenlabs")
|
||||
if not api_key:
|
||||
return {"success": False, "transcript": "", "error": "ELEVENLABS_API_KEY not set"}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,30 @@ def get_env_value(name, default=None):
|
|||
return os.getenv(name, default)
|
||||
value = _get_env_value(name)
|
||||
return default if value is None else value
|
||||
|
||||
|
||||
def _resolve_provider_key(env_var: str, provider_id: str) -> str:
|
||||
"""Resolve an API key from env, .env, or the credential pool.
|
||||
|
||||
Used by TTS providers (Mistral, ElevenLabs) that store keys
|
||||
via ``hermes auth add <provider_id>``.
|
||||
"""
|
||||
key = get_env_value(env_var)
|
||||
if key:
|
||||
return key
|
||||
try:
|
||||
from agent.credential_pool import load_pool
|
||||
pool = load_pool(provider_id)
|
||||
if pool and pool.has_credentials():
|
||||
entry = pool.peek()
|
||||
if entry:
|
||||
key = getattr(entry, "access_token", "") or getattr(entry, "runtime_api_key", "")
|
||||
key = str(key).strip()
|
||||
if key:
|
||||
return key
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
from tools.managed_tool_gateway import resolve_managed_tool_gateway
|
||||
from tools.tool_backend_helpers import (
|
||||
managed_nous_tools_enabled,
|
||||
|
|
@ -1092,7 +1116,7 @@ def _generate_elevenlabs(text: str, output_path: str, tts_config: Dict[str, Any]
|
|||
Returns:
|
||||
Path to the saved audio file.
|
||||
"""
|
||||
api_key = (get_env_value("ELEVENLABS_API_KEY") or "")
|
||||
api_key = (_resolve_provider_key("ELEVENLABS_API_KEY", "elevenlabs") or "")
|
||||
if not api_key:
|
||||
raise ValueError("ELEVENLABS_API_KEY not set. Get one at https://elevenlabs.io/")
|
||||
|
||||
|
|
@ -1663,7 +1687,7 @@ def _generate_mistral_tts(text: str, output_path: str, tts_config: Dict[str, Any
|
|||
and writes the raw bytes to *output_path*.
|
||||
Supports native Opus output for Telegram voice bubbles.
|
||||
"""
|
||||
api_key = (get_env_value("MISTRAL_API_KEY") or "")
|
||||
api_key = (_resolve_provider_key("MISTRAL_API_KEY", "mistral") or "")
|
||||
if not api_key:
|
||||
raise ValueError("MISTRAL_API_KEY not set. Get one at https://console.mistral.ai/")
|
||||
|
||||
|
|
@ -2746,7 +2770,7 @@ def check_tts_requirements() -> bool:
|
|||
_import_elevenlabs()
|
||||
except ImportError:
|
||||
return False
|
||||
return bool(get_env_value("ELEVENLABS_API_KEY"))
|
||||
return bool(_resolve_provider_key("ELEVENLABS_API_KEY", "elevenlabs"))
|
||||
if provider == "openai":
|
||||
try:
|
||||
_import_openai_client()
|
||||
|
|
@ -2775,7 +2799,7 @@ def check_tts_requirements() -> bool:
|
|||
_import_mistral_client()
|
||||
except ImportError:
|
||||
return False
|
||||
return bool(get_env_value("MISTRAL_API_KEY"))
|
||||
return bool(_resolve_provider_key("MISTRAL_API_KEY", "mistral"))
|
||||
if provider == "neutts":
|
||||
return _check_neutts_available()
|
||||
if provider == "kittentts":
|
||||
|
|
@ -3074,7 +3098,7 @@ if __name__ == "__main__":
|
|||
print("\nProvider availability:")
|
||||
print(f" Edge TTS: {'installed' if _check(_import_edge_tts, 'edge') else 'not installed (pip install edge-tts)'}")
|
||||
print(f" ElevenLabs: {'installed' if _check(_import_elevenlabs, 'el') else 'not installed (pip install elevenlabs)'}")
|
||||
print(f" API Key: {'set' if get_env_value('ELEVENLABS_API_KEY') else 'not set'}")
|
||||
print(f" API Key: {'set' if _resolve_provider_key('ELEVENLABS_API_KEY', 'elevenlabs') else 'not set'}")
|
||||
print(f" OpenAI: {'installed' if _check(_import_openai_client, 'oai') else 'not installed'}")
|
||||
print(
|
||||
" API Key: "
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue