Cloud STT model names breaking local faster-whisper provider

NousResearch/hermes-agent · cluster 2544 · gateway

Data as of

Nothing open on GitHub. Fix merged in #13016. Check it covers your case.

The short answer

0open issues
0open PRs
5items grouped
Known?
Yes. 5 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #13016. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this resolved, deciding PR #13016. That is separate from the fix event.
Still open
Nothing open on GitHub.

A bug where cloud-only model names like 'whisper-1' cause crashes when passed to the local faster-whisper provider. Multiple fix attempts address mapping or normalizing these names to valid local model sizes.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #13016 fix(stt): map cloud-only model names to valid local size for faster-whisper (#2544)

    merged to main

    files: scripts/release.py, tests/tools/test_transcription.py, tools/transcription_tools.py

    Show the diff
    • scripts/release.py
      @@ -80,6 +80,7 @@
           "[redacted:email]": "jplew",
           "[redacted:email]": "nish3451",
           "[redacted:email]": "Mibayy",
      +    "[redacted:email]": "Mibayy",
           "[redacted:email]": "sgaofen",
           "[redacted:email]": "nocoo",
           "[redacted:email]": "n-WN",
    • tests/tools/test_transcription.py
      @@ -245,3 +245,67 @@ def test_invalid_file_returns_error(self):
               result = transcribe_audio("/nonexistent/file.ogg")
               assert result["success"] is False
               assert "not found" in result["error"]
      +
      +
      +# ---------------------------------------------------------------------------
      +# Model name normalisation for local providers
      +# ---------------------------------------------------------------------------
      +
      +
      +class TestNormalizeLocalModel:
      +    """_normalize_local_model() maps cloud-only names to the local default."""
      +
      +    def test_openai_model_name_maps_to_default(self):
      +        from tools.transcription_tools import _normalize_local_model, DEFAULT_LOCAL_MODEL
      +        assert _normalize_local_model("whisper-1") == DEFAULT_LOCAL_MODEL
      +
      +    def test_groq_model_name_maps_to_default(self):
      +        from tools.transcription_tools import _normalize_local_model, DEFAULT_LOCAL_MODEL
      +        assert _normalize_local_model("whisper-large-v3-turbo") == DEFAULT_LOCAL_MODEL
      +
      +    def test_valid_local_model_preserved(self):
      +        from tools.transcription_tools import _normalize_local_model
      +        for size in ("tiny", "base", "small", "medium", "large-v3"):
      +            assert _normalize_local_model(size) == size
      +
      +    def test_none_maps_to_default(self):
      +        from tools.transcription_tools import _normalize_local_model, DEFAULT_LOCAL_MODEL
      +        assert _normalize_local_model(None) == DEFAULT_LOCAL_MODEL
      +
      +    def test_warning_emitted_for_cloud_model(self, caplog):
      +        import logging
      +        from tools.transcription_tools import _normalize_local_model
      +        with caplog.at_level(logging.WARNING, logger="tools.transcription_tools"):
      +            _normalize_local_model("whisper-1")
      +        assert any("whisper-1" in r.message for r in caplog.records)
      +
      +    def test_local_transcribe_normalises_model(self):
      +        """transcribe_audio with local provider must not pass 'whisper-1' to WhisperModel."""
      +        import tempfile, os
      +        from unittest.mock import MagicMock, patch
      +
      +        with tempfile.NamedTemporaryFile(suffix=".ogg", delete=False) as f:
      +            f.write(b"x")
      +            audio_file = f.name
      +        try:
      +            mock_model = MagicMock()
      +            mock_model.transcribe.return_value = (iter([]), MagicMock(language="en", duration=1.0))
      +            with patch("tools.transcription_tools._HAS_FASTER_WHISPER", True), \
      +                 patch("tools.transcription_tools._load_stt_config", return_value={
      +                     "enabled": True,
      +                     "provider": "local",
      +                     "local": {"model": "whisper-1"},
      +                 }), \
      +                 patch("tools.transcription_tools._local_model", None), \
      +                 patch("tools.transcription_tools._local_model_name", None), \
      +                 patch("faster_whisper.WhisperModel", return_value=mock_model) as mock_cls:
      +                from tools.transcription_tools import transcribe_audio
      +                transcribe_audio(audio_file)
      +                # WhisperModel must NOT have been called with "whisper-1"
      +                call_args = mock_cls.call_args
      +                assert call_args is not None
      +                assert call_args[0][0] != "whisper-1", (
      +                    "WhisperModel was called with the cloud-only name 'whisper-1'"
      +                )
      +        finally:
      +            os.unlink(audio_file)
    • tools/transcription_tools.py
      @@ -154,12 +154,31 @@ def _has_local_command() -> bool:
           return _get_local_command_template() is not None
       
       
      -def _normalize_local_command_model(model_name: Optional[str]) -> str:
      +def _normalize_local_model(model_name: Optional[str]) -> str:
      +    """Return a valid faster-whisper model size, mapping cloud-only names to the default.
      +
      +    Cloud providers like OpenAI use names such as ``whisper-1`` which are not
      +    valid for faster-whisper (which expects ``tiny``, ``base``, ``small``,
      +    ``medium``, or ``large-v*``).  When such a name is detected we fall back to
      +    the default local model and emit a warning so the user knows what happened.
      +    """
           if not model_name or model_name in OPENAI_MODELS or model_name in GROQ_MODELS:
      +        if model_name and (model_name in OPENAI_MODELS or model_name in GROQ_MODELS):
      +            logger.warning(
      +                "STT model '%s' is a cloud-only name and cannot be used with the local "
      +                "provider. Falling back to '%s'. Set stt.local.model to a valid "
      +                "faster-whisper size (tiny, base, small, medium, large-v3).",
      +                model_name,
      +                DEFAULT_LOCAL_MODEL,
      +            )
               return DEFAULT_LOCAL_MODEL
           return model_name
       
       
      +def _normalize_local_command_model(model_name: Optional[str]) -> str:
      +    return _normalize_local_model(model_name)
      +
      +
       def _get_provider(stt_config: dict) -> str:
           """Determine which STT provider to use.
       
      @@ -596,7 +615,9 @@ def transcribe_audio(file_path: str, model: Optional[str] = None) -> Dict[str, A
       
           if provider == "local":
               local_cfg = stt_config.get("local", {})
      -        model_name = model or local_cfg.get("model", DEFAULT_LOCAL_MODEL)
      +        model_name = _normalize_local_model(
      +            model or local_cfg.get("model", DEFAULT_LOCAL_MODEL)
      +        )
               return _transcribe_local(file_path, model_name)
       
           if provider == "local_command":

3 PRs closed without merging

From the close comments: superseded by another PR 2 · merged via another change 1

  • #2545 fix(stt): map cloud-only model names to valid local size for faster-whisper · merged via another change → #13016
  • #2731 fix(stt): map cloud-only model names to default local model for faster-whisper · superseded by another PR → #13016
  • #11618 fix(stt): normalize cloud-only model names for local faster-whisper provider · superseded by another PR → #13016
Closed issues · 1
  • Closed#2544[Bug]: Local STT provider crashes when config contains OpenAI model name ("whisper-1")
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.40: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
gateway
Merged PRs
#13016
Closed issues
1
Attempts
3 PRs closed without merging
Fix link checked
20 Apr 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.

For your agent

The same facts, typed.