mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix: allow voice mode in WSL when PulseAudio bridge is configured
WSL detection was treated as a hard fail, blocking voice mode even when audio worked via PulseAudio bridge. Now PULSE_SERVER env var presence makes WSL a soft notice instead of a blocking warning. Device query failures in WSL with PULSE_SERVER are also treated as non-blocking.
This commit is contained in:
parent
7f670a06cf
commit
08171c1c31
2 changed files with 153 additions and 5 deletions
|
|
@ -56,6 +56,134 @@ def mock_sd(monkeypatch):
|
|||
return mock
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# detect_audio_environment — WSL / SSH / Docker detection
|
||||
# ============================================================================
|
||||
|
||||
class TestDetectAudioEnvironment:
|
||||
def test_clean_environment_is_available(self, monkeypatch):
|
||||
"""No SSH, Docker, or WSL — should be available."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (MagicMock(), MagicMock()))
|
||||
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
assert result["available"] is True
|
||||
assert result["warnings"] == []
|
||||
|
||||
def test_ssh_blocks_voice(self, monkeypatch):
|
||||
"""SSH environment should block voice mode."""
|
||||
monkeypatch.setenv("SSH_CLIENT", "1.2.3.4 54321 22")
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (MagicMock(), MagicMock()))
|
||||
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
assert result["available"] is False
|
||||
assert any("SSH" in w for w in result["warnings"])
|
||||
|
||||
def test_wsl_without_pulse_blocks_voice(self, monkeypatch, tmp_path):
|
||||
"""WSL without PULSE_SERVER should block voice mode."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.delenv("PULSE_SERVER", raising=False)
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (MagicMock(), MagicMock()))
|
||||
|
||||
proc_version = tmp_path / "proc_version"
|
||||
proc_version.write_text("Linux 5.15.0-microsoft-standard-WSL2")
|
||||
|
||||
_real_open = open
|
||||
def _fake_open(f, *a, **kw):
|
||||
if f == "/proc/version":
|
||||
return _real_open(str(proc_version), *a, **kw)
|
||||
return _real_open(f, *a, **kw)
|
||||
|
||||
with patch("builtins.open", side_effect=_fake_open):
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
|
||||
assert result["available"] is False
|
||||
assert any("WSL" in w for w in result["warnings"])
|
||||
assert any("PulseAudio" in w for w in result["warnings"])
|
||||
|
||||
def test_wsl_with_pulse_allows_voice(self, monkeypatch, tmp_path):
|
||||
"""WSL with PULSE_SERVER set should NOT block voice mode."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.setenv("PULSE_SERVER", "unix:/mnt/wslg/PulseServer")
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (MagicMock(), MagicMock()))
|
||||
|
||||
proc_version = tmp_path / "proc_version"
|
||||
proc_version.write_text("Linux 5.15.0-microsoft-standard-WSL2")
|
||||
|
||||
_real_open = open
|
||||
def _fake_open(f, *a, **kw):
|
||||
if f == "/proc/version":
|
||||
return _real_open(str(proc_version), *a, **kw)
|
||||
return _real_open(f, *a, **kw)
|
||||
|
||||
with patch("builtins.open", side_effect=_fake_open):
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
|
||||
assert result["available"] is True
|
||||
assert result["warnings"] == []
|
||||
assert any("WSL" in n for n in result.get("notices", []))
|
||||
|
||||
def test_wsl_device_query_fails_with_pulse_continues(self, monkeypatch, tmp_path):
|
||||
"""WSL device query failure should not block if PULSE_SERVER is set."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.setenv("PULSE_SERVER", "unix:/mnt/wslg/PulseServer")
|
||||
|
||||
mock_sd = MagicMock()
|
||||
mock_sd.query_devices.side_effect = Exception("device query failed")
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (mock_sd, MagicMock()))
|
||||
|
||||
proc_version = tmp_path / "proc_version"
|
||||
proc_version.write_text("Linux 5.15.0-microsoft-standard-WSL2")
|
||||
|
||||
_real_open = open
|
||||
def _fake_open(f, *a, **kw):
|
||||
if f == "/proc/version":
|
||||
return _real_open(str(proc_version), *a, **kw)
|
||||
return _real_open(f, *a, **kw)
|
||||
|
||||
with patch("builtins.open", side_effect=_fake_open):
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
|
||||
assert result["available"] is True
|
||||
assert any("device query failed" in n for n in result.get("notices", []))
|
||||
|
||||
def test_device_query_fails_without_pulse_blocks(self, monkeypatch):
|
||||
"""Device query failure without PULSE_SERVER should block."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.delenv("PULSE_SERVER", raising=False)
|
||||
|
||||
mock_sd = MagicMock()
|
||||
mock_sd.query_devices.side_effect = Exception("device query failed")
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (mock_sd, MagicMock()))
|
||||
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
|
||||
assert result["available"] is False
|
||||
assert any("PortAudio" in w for w in result["warnings"])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# check_voice_requirements
|
||||
# ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue