Skip to content

fix(tts): read tts.openai.api_key/base_url from config.yaml before env vars - #26209

Closed
zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:fix/tts-openai-config-read-26175
Closed

zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:fix/tts-openai-config-read-26175

Conversation

@zccyman

@zccyman zccyman commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

_resolve_openai_audio_client_config() was env-only — it read VOICE_TOOLS_OPENAI_KEY / OPENAI_API_KEY and always returned DEFAULT_OPENAI_BASE_URL, ignoring tts.openai.api_key and tts.openai.base_url from config.yaml.

Closes #26175

Problem

Users pointing TTS at a self-hosted or local OpenAI-compatible endpoint (llama.cpp, qwen3-tts, Ollama, etc.) either need a placeholder env var (and still cannot redirect the host) or get no audio at all — even with a fully-populated tts.openai config block.

Solution

Mirror the STT resolver order used in transcription_tools.py::_resolve_openai_audio_client_config:

  1. Config — read tts.openai.api_key + tts.openai.base_url from config.yaml via existing _load_tts_config()
  2. Env var — existing resolve_openai_audio_api_key() fallback (now also respects cfg_base_url instead of hardcoding DEFAULT_OPENAI_BASE_URL)
  3. Managed gateway — existing fallback with prefers_gateway("tts") check

Preserves the existing tts.use_gateway preference — when set, the managed gateway is preferred even if credentials exist.

Updated the error message to mention config as well: "Neither tts.openai.api_key in config nor VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY is set"

Files Changed

File Change
tools/tts_tool.py Add config-first resolution to _resolve_openai_audio_client_config()

Test Results

tests/tools/test_tts_speed.py ........... 19 passed
tests/tools/test_transcription_tools.py ...... 95 passed
tests/tools -k "tts" .................. 182 passed

Design Decisions

  • Uses the existing _load_tts_config() helper (was already defined but unused by this function)
  • Config base_url is also respected from the env-var fallback path, unlike the previous code which hardcoded DEFAULT_OPENAI_BASE_URL
  • prefers_gateway("tts") check is preserved on both config and env-var paths

@zccyman zccyman closed this May 15, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/tts Text-to-speech and transcription area/config Config system, migrations, profiles labels May 15, 2026
@zccyman zccyman reopened this May 15, 2026
NishantEC

This comment was marked as outdated.

@zccyman

zccyman commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @NishantEC for the review! Appreciate the approval on the TTS config fix. 🙏

…v vars

_resolve_openai_audio_client_config was env-only: it read
VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY and returned DEFAULT_OPENAI_BASE_URL,
ignoring tts.openai.api_key and tts.openai.base_url from config.yaml.

Mirror the STT resolver order (config → env → managed gateway):
1. tts.openai.api_key/base_url from config.yaml
2. VOICE_TOOLS_OPENAI_KEY / OPENAI_API_KEY env vars
3. Managed OpenAI audio gateway (with prefers_gateway("tts") check)

Also preserves config base_url in the env-var fallback path (previously
used hardcoded DEFAULT_OPENAI_BASE_URL even when cfg_base_url was set).

Closes NousResearch#26175
@zccyman
zccyman force-pushed the fix/tts-openai-config-read-26175 branch from b906130 to 91ae77a Compare May 18, 2026 00:32
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for targeting the config-only OpenAI TTS path. The premise is confirmed on current main: tools/tts_tool.py:2533-2535 still only resolves env credentials, while tools/tts_tool.py:1027 calls that resolver before applying tts.openai.base_url at :1032-1034.

Problems

  • Current main changed this resolver to return (api_key, base_url, is_managed) in commit b53ba0e18; its caller unpacks three values at tools/tts_tool.py:1027. Salvage the config and env direct paths with is_managed=False.
  • Config-only credentials also need to reach check_tts_requirements(): its OpenAI branch calls _has_openai_audio_backend() (tools/tts_tool.py:2494-2496), which currently only checks env credentials or the managed gateway (:2556-2558). The registered tool uses that check at :2868.
  • Please add regression coverage for config-only resolution and availability; this PR currently changes no tests.

Suggested changes

  • Reconcile the resolver with the current three-value contract and extend the availability predicate to recognize tts.openai.api_key, preserving tts.use_gateway behavior.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
teknium1 pushed a commit that referenced this pull request Jul 28, 2026
Salvaged from PR #26233 (@LeonSGP43), rebased onto the current 3-tuple
_resolve_openai_audio_client_config (is_managed flag, post-#73072 layout).
Same fix independently submitted earlier in PR #26209 (@zccyman) — credit
to both.

Resolution order now mirrors the STT resolver: tts.openai.api_key/base_url
from config.yaml -> VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY env (still
honoring config base_url) -> managed gateway. _has_openai_audio_backend
also counts a config api_key as an available backend.

Fixes #26175
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Salvaged from PR NousResearch#26233 (@LeonSGP43), rebased onto the current 3-tuple
_resolve_openai_audio_client_config (is_managed flag, post-NousResearch#73072 layout).
Same fix independently submitted earlier in PR NousResearch#26209 (@zccyman) — credit
to both.

Resolution order now mirrors the STT resolver: tts.openai.api_key/base_url
from config.yaml -> VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY env (still
honoring config base_url) -> managed gateway. _has_openai_audio_backend
also counts a config api_key as an available backend.

Fixes NousResearch#26175
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
Salvaged from PR NousResearch#26233 (@LeonSGP43), rebased onto the current 3-tuple
_resolve_openai_audio_client_config (is_managed flag, post-NousResearch#73072 layout).
Same fix independently submitted earlier in PR NousResearch#26209 (@zccyman) — credit
to both.

Resolution order now mirrors the STT resolver: tts.openai.api_key/base_url
from config.yaml -> VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY env (still
honoring config base_url) -> managed gateway. _has_openai_audio_backend
also counts a config api_key as an available backend.

Fixes NousResearch#26175
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
Salvaged from PR NousResearch#26233 (@LeonSGP43), rebased onto the current 3-tuple
_resolve_openai_audio_client_config (is_managed flag, post-NousResearch#73072 layout).
Same fix independently submitted earlier in PR NousResearch#26209 (@zccyman) — credit
to both.

Resolution order now mirrors the STT resolver: tts.openai.api_key/base_url
from config.yaml -> VOICE_TOOLS_OPENAI_KEY/OPENAI_API_KEY env (still
honoring config base_url) -> managed gateway. _has_openai_audio_backend
also counts a config api_key as an available backend.

Fixes NousResearch#26175
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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.

TTS tool ignores tts.openai.api_key / tts.openai.base_url in config.yaml — config-only setups cannot reach self-hosted endpoints

4 participants