From db5d406d887062726e8984b3fb3b2e3dda04fa20 Mon Sep 17 00:00:00 2001 From: Rod Boev Date: Mon, 29 Jun 2026 17:36:51 -0400 Subject: [PATCH] fix(boot): restore voice-mode runtime prefs during prefill rework (#4961) --- static/boot.js | 10 ++++++-- .../test_issue1488_composer_voice_buttons.py | 25 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/static/boot.js b/static/boot.js index 9c3aaa5d..7f378136 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1041,7 +1041,13 @@ window._hermesTtsSynth=function(id, text, opts){ let _browserTtsKeepAlive=null; let _browserTtsWatchdog=null; let _browserTtsSuppressNextErrorRearm=false; - const SILENCE_MS=1800; // auto-send after 1.8s silence + // Configurable via localStorage keys (set from dev console or a future settings panel). + // hermes-voice-silence-ms — pause duration before auto-send (ms, default 1800) + // hermes-voice-continuous — keep mic open across natural pauses ("true"/"false", default false) + const _silenceMsRaw=parseInt(localStorage.getItem('hermes-voice-silence-ms'),10); + // Fall back to 1800 for missing/NaN/non-positive values, and floor at 200ms so a + // mistyped tiny/negative value can't make the recognizer auto-send instantly. + const SILENCE_MS=(Number.isFinite(_silenceMsRaw)&&_silenceMsRaw>0)?Math.max(200,_silenceMsRaw):1800; function _clearBrowserTtsRecovery(){ if(_browserTtsKeepAlive){ @@ -1101,7 +1107,7 @@ window._hermesTtsSynth=function(id, text, opts){ _setState('listening'); _recognition=new SpeechRecognition(); - _recognition.continuous=false; + _recognition.continuous=localStorage.getItem('hermes-voice-continuous')==='true'; _recognition.interimResults=true; _recognition.lang=(typeof _locale!=='undefined'&&_locale._speech)||'en-US'; diff --git a/tests/test_issue1488_composer_voice_buttons.py b/tests/test_issue1488_composer_voice_buttons.py index 7cd02c2f..134b0990 100644 --- a/tests/test_issue1488_composer_voice_buttons.py +++ b/tests/test_issue1488_composer_voice_buttons.py @@ -232,6 +232,31 @@ class TestVoiceModePreferenceGate: "so the button appears/disappears immediately." +class TestVoiceModeRuntimePreferences: + """Voice mode runtime prefs must stay wired to localStorage-backed settings.""" + + def test_voice_mode_silence_pref_reads_localstorage_with_floor(self): + """boot.js must keep the silence timeout configurable without allowing + tiny or invalid values to auto-send instantly.""" + src = _src("boot.js") + assert "localStorage.getItem('hermes-voice-silence-ms')" in src, ( + "voice mode must read hermes-voice-silence-ms from localStorage " + "so pause timing survives reloads." + ) + assert "Math.max(200,_silenceMsRaw)" in src, ( + "voice mode must floor the configured silence timeout at 200ms " + "instead of trusting tiny values." + ) + + def test_voice_mode_continuous_pref_reads_localstorage(self): + """boot.js must preserve the continuous-recognition preference across reloads.""" + src = _src("boot.js") + assert "localStorage.getItem('hermes-voice-continuous')==='true'" in src, ( + "voice mode must read hermes-voice-continuous from localStorage " + "instead of hardcoding continuous recognition off." + ) + + class TestActiveStateTooltips: """When recording / in voice mode, tooltips should flip to the 'stop' variants so the affordance is honest."""