diff --git a/tests/tools/test_wake_word.py b/tests/tools/test_wake_word.py index 0ac450f5c5..469f823531 100644 --- a/tests/tools/test_wake_word.py +++ b/tests/tools/test_wake_word.py @@ -641,7 +641,11 @@ def test_resolve_capture_mode_auto_and_prefer_client(monkeypatch): assert ww.resolve_capture_mode({"capture": "auto"}, force_local=True) == "local" monkeypatch.setattr(ww, "_local_input_device_ready", lambda: True) assert ww.resolve_capture_mode({"capture": "auto"}) == "local" - assert ww.resolve_capture_mode({"capture": "auto"}, prefer_client=True) == "client" + # A working backend mic wins under auto even for a preferring surface, so + # local desktops keep PortAudio + wake_word.input_device selection. + assert ww.resolve_capture_mode({"capture": "auto"}, prefer_client=True) == "local" + # Explicit client still forces streaming (backend mic exists but is wrong). + assert ww.resolve_capture_mode({"capture": "client"}, prefer_client=True) == "client" def test_requirements_client_capture_without_local_mic(monkeypatch): @@ -674,7 +678,7 @@ def test_requirements_client_capture_without_local_mic(monkeypatch): def test_client_capture_feed_fires(monkeypatch, tmp_path): - import numpy as np + np = pytest.importorskip("numpy") monkeypatch.setattr(ww, "_build_engine", lambda cfg: _FakeEngine(fire=True)) monkeypatch.setattr(ww, "_lock_path", lambda: tmp_path / "wake.lock") diff --git a/tools/wake_word.py b/tools/wake_word.py index b71c47cb0b..960bed50e2 100644 --- a/tools/wake_word.py +++ b/tools/wake_word.py @@ -269,15 +269,17 @@ def resolve_capture_mode( return "client" if raw == "local": return "local" - # auto - if prefer_client: - return "client" - # Prefer local when a PortAudio input exists. Without an explicit client - # preference (desktop remote), stay on local so CLI/TUI/status still - # require a server mic instead of advertising a capture path only the - # desktop can feed. + # auto: a working backend input always wins so local desktops keep + # PortAudio and the configured ``input_device`` selection. Client capture + # is the fallback for a preferring surface (desktop remote) on a backend + # with no usable mic — the headless VPS/Cloud case. if _local_input_device_ready(): return "local" + if prefer_client: + return "client" + # No local mic and no client preference (CLI/TUI): stay local so status + # reports the real requirement instead of advertising a capture path + # nothing will feed. return "local"