fix(stt): respect explicit provider config instead of env-var fallback (#1775)

* fix(session): skip corrupt lines in load_transcript instead of crashing

Wrap json.loads() in load_transcript() with try/except JSONDecodeError
so that partial JSONL lines (from mid-write crashes like OOM/SIGKILL)
are skipped with a warning instead of crashing the entire transcript
load. The rest of the history loads fine.

Adds a logger.warning with the session ID and truncated corrupt line
content for debugging visibility.

Salvaged from PR #1193 by alireza78a.
Closes #1193

* fix(stt): respect explicit provider config instead of env-var fallback

Rework _get_provider() to separate explicit config from auto-detect.
When stt.provider is explicitly set in config.yaml, that choice is
authoritative — no silent cross-provider fallback based on which env
vars happen to be set. When no provider is configured, auto-detect
still tries: local > groq > openai.

This fixes the reported scenario where provider: local + a placeholder
OPENAI_API_KEY caused the system to silently select OpenAI and fail
with a 401.

Closes #1774
This commit is contained in:
Teknium 2026-03-17 10:30:58 -07:00 committed by GitHub
parent 088d65605a
commit 9a1e971126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 151 additions and 115 deletions

View file

@ -26,13 +26,14 @@ class TestGetProvider:
from tools.transcription_tools import _get_provider
assert _get_provider({"provider": "local"}) == "local"
def test_local_fallback_to_openai(self, monkeypatch):
def test_explicit_local_no_cloud_fallback(self, monkeypatch):
"""Explicit local provider must not silently fall back to cloud."""
monkeypatch.setenv("VOICE_TOOLS_OPENAI_KEY", "sk-test")
monkeypatch.delenv("GROQ_API_KEY", raising=False)
with patch("tools.transcription_tools._HAS_FASTER_WHISPER", False), \
patch("tools.transcription_tools._HAS_OPENAI", True):
from tools.transcription_tools import _get_provider
assert _get_provider({"provider": "local"}) == "openai"
assert _get_provider({"provider": "local"}) == "none"
def test_local_nothing_available(self, monkeypatch):
monkeypatch.delenv("VOICE_TOOLS_OPENAI_KEY", raising=False)
@ -47,12 +48,13 @@ class TestGetProvider:
from tools.transcription_tools import _get_provider
assert _get_provider({"provider": "openai"}) == "openai"
def test_openai_fallback_to_local(self, monkeypatch):
def test_explicit_openai_no_key_returns_none(self, monkeypatch):
"""Explicit openai without key returns none — no cross-provider fallback."""
monkeypatch.delenv("VOICE_TOOLS_OPENAI_KEY", raising=False)
with patch("tools.transcription_tools._HAS_FASTER_WHISPER", True), \
patch("tools.transcription_tools._HAS_OPENAI", True):
from tools.transcription_tools import _get_provider
assert _get_provider({"provider": "openai"}) == "local"
assert _get_provider({"provider": "openai"}) == "none"
def test_default_provider_is_local(self):
with patch("tools.transcription_tools._HAS_FASTER_WHISPER", True):