Skip to content

fix(voice): resolve API keys from ~/.hermes/.env in TTS + STT tools (#17140)#17434

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-94703785
Apr 29, 2026
Merged

fix(voice): resolve API keys from ~/.hermes/.env in TTS + STT tools (#17140)#17434
teknium1 merged 3 commits into
mainfrom
hermes/hermes-94703785

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Users with TTS/STT API keys only in ~/.hermes/.env can now use every voice backend. Salvages #17163 (@briandevans, TTS variant) and widens the same fix to the sibling file tools/transcription_tools.py (STT variant — identical bug class, untouched by the original PR).

Same class of bug as #15914 / #15920 (auth.py + agent/credential_pool variants) — os.getenv() misses keys that only live in ~/.hermes/.env. hermes_cli.config.get_env_value() is the canonical resolver (env first, dotenv fallback).

Changes

  • tools/tts_tool.py (@briandevans, cherry-picked as-is from fix(tts): resolve API keys from ~/.hermes/.env via get_env_value (#17140) #17163): 13 call sites across ElevenLabs, xAI, MiniMax, Mistral, Gemini — all API-key / paired-base-URL lookups and the check_tts_requirements() gate.
  • tools/transcription_tools.py (new in this PR): 9 call sites across _transcribe_groq, _transcribe_mistral, _transcribe_xai, and the _get_provider selection gate. Module-level constants (DEFAULT_STT_MODEL, GROQ_BASE_URL, etc.) intentionally stay on os.getenv — they're import-time defaults, not runtime-resolved config.
  • tests/tools/test_tts_dotenv_fallback.py (@briandevans): 7 tests.
  • tests/tools/test_transcription_dotenv_fallback.py (new): 8 tests mirroring the TTS pattern — per-provider key forwarding, selection-gate dotenv visibility, and an end-to-end probe patching hermes_cli.config.load_env to simulate ~/.hermes/.env-only keys.

Both files use the same guarded import pattern as tools/tool_backend_helpers.py::fal_key_is_configured:

try:
    from hermes_cli.config import get_env_value
except ImportError:
    def get_env_value(name, default=None):
        return os.getenv(name, default)

Validation

Before After
tests/tools/test_tts_dotenv_fallback.py 7 failures (pre-fix baseline) 7 passed
tests/tools/test_transcription_dotenv_fallback.py 8 failures (pre-fix baseline) 8 passed
Regression guard Reverting tools/transcription_tools.py re-triggers all 8 new failures verified
scripts/run_tests.sh tests/tools/test_tts_dotenv_fallback.py tests/tools/test_transcription_dotenv_fallback.py
# 15 passed in 0.88s

Authorship

  • @briandevans commits preserved via rebase-merge — fix(tts): resolve API keys from ~/.hermes/.env via get_env_value (#17140) and fix(tts): tolerate missing hermes_cli.config in tts_tool import (Copilot review follow-up).
  • The STT widening commit is ours.

Related

briandevans and others added 3 commits April 29, 2026 05:01
)

TTS provider tools (elevenlabs, xai, minimax, mistral, gemini) called
os.getenv("X_API_KEY") directly, which bypassed Hermes's dotenv bridge in
hermes_cli.config. Users who keep their TTS keys only in ~/.hermes/.env saw
"X_API_KEY not set" errors even though the rest of the stack
(agent/credential_pool, hermes_cli/auth) already resolves keys through
get_env_value() — same class of bug as #15914 fixed for those modules.

Switch every TTS env-var lookup (API keys, base URLs, and
check_tts_requirements gates) to get_env_value, which checks os.environ
first and then ~/.hermes/.env. Behaviour for users with keys exported in
the shell is unchanged; users with dotenv-only keys now succeed. The two
diagnostics prints in __main__ are migrated for consistency.

Regression test (tests/tools/test_tts_dotenv_fallback.py):
  - per-provider: each backend reads the dotenv key when only
    ~/.hermes/.env carries it (5 providers).
  - end-to-end: with hermes_cli.config.load_env returning the key and
    os.environ empty, _generate_minimax_tts and check_tts_requirements
    both succeed; reverting tools/tts_tool.py back to os.getenv makes all
    7 tests fail with "MINIMAX_API_KEY not set" / similar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the new top-level `from hermes_cli.config import get_env_value`
in try/except ImportError and fall back to a thin os.getenv shim, so
importing tools.tts_tool keeps working in environments where
hermes_cli.config is unavailable. This matches the existing tolerance
in `_load_tts_config()` (tools/tts_tool.py) and the same
import-fallback pattern in tools/tool_backend_helpers.py::fal_key_is_configured.

Also update the TestDotenvFallbackPerProvider docstring to accurately
describe the mocking strategy: per-provider tests patch
`tools.tts_tool.get_env_value` directly, while the regression-guard
tests cover the lower-level `hermes_cli.config.load_env` integration.

Addresses Copilot review on #17163.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
)

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.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tools Tool registry, model_tools, toolsets tool/tts Text-to-speech and transcription labels Apr 29, 2026
@teknium1 teknium1 merged commit 9e63062 into main Apr 29, 2026
11 of 12 checks passed
@teknium1 teknium1 deleted the hermes/hermes-94703785 branch April 29, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists tool/tts Text-to-speech and transcription type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: TTS tools fail to read API keys from ~/.hermes/.env — os.getenv() doesn't see dotenv values

3 participants