fix(voice): recognize command STT providers in capability probe (#4312)

The /api/transcribe/capability probe's resolve_provider() only knew the
built-in STT providers, so an explicit stt.provider mapping to a Hermes
command-type provider was reported unavailable and the browser fell back
unnecessarily. Add command_provider_available(), delegating to the agent's
_resolve_command_stt_provider_config(provider, cfg) as the single source of
truth, consulted as the final fallthrough after the built-in chain (the
agent rejects built-in names internally, so ordering can't shadow a native
provider). Added a clarifying comment that command providers are
intentionally omitted from the auto-detect tuple to match the agent's
_get_provider() precedence.

Co-authored-by: LLMinem <LLMinem@users.noreply.github.com>
This commit is contained in:
nesquena-hermesandLLMinem committed 2026-06-16 17:21:11 +00:00
1 parent b73e18cc23
commit ed7bd05530
2 files changed
+43

No files matched your search

+15
View File
@@ -457,6 +457,13 @@ def _stt_provider_capability_from_module(stt):
# non-WAV input through ffmpeg before invoking the command.
return has_local_command() and has_browser_audio_converter()
def command_provider_available(provider):
resolver = getattr(stt, "_resolve_command_stt_provider_config", None)
try:
return callable(resolver) and resolver(provider, cfg_dict) is not None
except Exception:
return False
def resolve_provider(provider):
if provider == "local":
if bool(getattr(stt, "_HAS_FASTER_WHISPER", False)):
@@ -485,6 +492,8 @@ def _stt_provider_capability_from_module(stt):
return "none"
if provider == "elevenlabs":
return "elevenlabs" if bool(env("ELEVENLABS_API_KEY")) else "none"
if command_provider_available(provider):
return provider
return "none"
explicit = "provider" in cfg_dict
@@ -494,6 +503,12 @@ def _stt_provider_capability_from_module(stt):
return provider != "none", provider if provider != "none" else configured
for candidate in ("local", "local_command", "groq", "openai", "mistral", "xai", "elevenlabs"):
# Command (custom) STT providers are intentionally omitted from this
# auto-detect tuple to mirror the agent's _get_provider() (transcription_tools.py),
# which only auto-selects local > groq > openai and never auto-picks a command
# provider. A command-backed STT activates only via an explicit stt.provider.
# Do NOT add command providers here without matching the agent, or the WebUI
# probe will diverge from what the agent actually resolves.
provider = resolve_provider(candidate)
if provider != "none":
return True, provider
+28
View File
@@ -156,3 +156,31 @@ def test_handle_transcribe_capability_reports_actual_local_command_fallback(monk
assert available is True
assert provider == "local_command"
def test_handle_transcribe_capability_reports_named_command_provider(monkeypatch):
stt_config = {
"provider": "elevenlabs-gemini",
"providers": {
"elevenlabs-gemini": {
"type": "command",
"command": "/home/user/.hermes/scripts/hermes-elevenlabs-stt.sh {input}",
}
},
}
fake_mod = types.ModuleType("tools.transcription_tools")
fake_mod.__dict__.update(
{
"_load_stt_config": lambda: stt_config,
"is_stt_enabled": lambda cfg=None: True,
"_HAS_FASTER_WHISPER": False,
"_HAS_OPENAI": False,
"_HAS_MISTRAL": False,
"_resolve_command_stt_provider_config": lambda provider, cfg: cfg["providers"].get(provider),
}
)
available, provider = _stt_provider_capability_from_module(fake_mod)
assert available is True
assert provider == "elevenlabs-gemini"