mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(voice): enforce voice.max_recording_seconds (was dead config)
This commit is contained in:
parent
ee5f20bdf2
commit
fd213a82f4
3 changed files with 65 additions and 0 deletions
11
cli.py
11
cli.py
|
|
@ -11766,6 +11766,17 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
|
|||
self._voice_recorder._silence_duration = (
|
||||
_duration if isinstance(_duration, (int, float)) and not isinstance(_duration, bool) else 3.0
|
||||
)
|
||||
# voice.max_recording_seconds — hard cap on a single recording's length.
|
||||
# Same numeric guard as the silence params (bool excluded: a hand-edited
|
||||
# ``max_recording_seconds: true`` must not become ``1``). <= 0 disables
|
||||
# the cap. Previously this documented key was never read, so the setting
|
||||
# had no effect (dead config); wiring it here makes it take effect.
|
||||
_max_rec = voice_cfg.get("max_recording_seconds")
|
||||
self._voice_recorder._max_recording_seconds = (
|
||||
_max_rec
|
||||
if isinstance(_max_rec, (int, float)) and not isinstance(_max_rec, bool) and _max_rec > 0
|
||||
else 0.0
|
||||
)
|
||||
|
||||
def _on_silence():
|
||||
"""Called by AudioRecorder when silence is detected after speech."""
|
||||
|
|
|
|||
32
tests/test_voice_max_recording_seconds.py
Normal file
32
tests/test_voice_max_recording_seconds.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""Regression test: voice.max_recording_seconds is actually enforced.
|
||||
|
||||
Before this fix, ``voice.max_recording_seconds`` was defined in the default
|
||||
config (hermes_cli/config.py) and documented, but no code read it — the
|
||||
AudioRecorder had no total-length cap, so the setting was dead config. This
|
||||
test pins the enforcement contract on the recorder:
|
||||
|
||||
* cap disabled (0 / unset) → never auto-stops on duration (previous behaviour),
|
||||
* cap set to N>0 → auto-stop condition becomes true once elapsed >= N.
|
||||
"""
|
||||
from tools.voice_mode import AudioRecorder
|
||||
|
||||
|
||||
def test_cap_disabled_by_default():
|
||||
r = AudioRecorder()
|
||||
assert r._max_recording_seconds == 0.0
|
||||
# No cap → duration trigger never fires, even at absurd elapsed times.
|
||||
assert r._max_duration_reached(10_000.0) is False
|
||||
|
||||
|
||||
def test_cap_enforced_when_set():
|
||||
r = AudioRecorder()
|
||||
r._max_recording_seconds = 120
|
||||
assert r._max_duration_reached(119.9) is False
|
||||
assert r._max_duration_reached(120.0) is True
|
||||
assert r._max_duration_reached(300.0) is True
|
||||
|
||||
|
||||
def test_zero_means_unlimited():
|
||||
r = AudioRecorder()
|
||||
r._max_recording_seconds = 0
|
||||
assert r._max_duration_reached(99_999.0) is False
|
||||
|
|
@ -497,11 +497,25 @@ class AudioRecorder:
|
|||
self._silence_threshold: int = SILENCE_RMS_THRESHOLD
|
||||
self._silence_duration: float = SILENCE_DURATION_SECONDS
|
||||
self._max_wait: float = 15.0 # Max seconds to wait for speech before auto-stop
|
||||
# Hard cap on total recording length, wired from voice.max_recording_seconds
|
||||
# by the CLI before each recording. 0 (or unset) = no cap (previous behaviour).
|
||||
self._max_recording_seconds: float = 0.0
|
||||
# Peak RMS seen during recording (for speech presence check in stop())
|
||||
self._peak_rms: int = 0
|
||||
# Live audio level (read by UI for visual feedback)
|
||||
self._current_rms: int = 0
|
||||
|
||||
def _max_duration_reached(self, elapsed: float) -> bool:
|
||||
"""Whether the configured hard recording-length cap has elapsed.
|
||||
|
||||
``voice.max_recording_seconds`` is applied by the CLI before each
|
||||
recording (see ``HermesCLI._voice_start_recording``). A value <= 0
|
||||
(or unset) disables the cap, preserving the previous unbounded
|
||||
behaviour.
|
||||
"""
|
||||
cap = self._max_recording_seconds
|
||||
return bool(cap and cap > 0 and elapsed >= cap)
|
||||
|
||||
# -- public properties ---------------------------------------------------
|
||||
|
||||
@property
|
||||
|
|
@ -618,6 +632,14 @@ class AudioRecorder:
|
|||
self._max_wait)
|
||||
should_fire = True
|
||||
|
||||
# 3. Hard cap on total recording length (voice.max_recording_seconds).
|
||||
# Independent of speech/silence so a continuous speaker past the
|
||||
# configured limit still auto-stops instead of recording forever.
|
||||
if not should_fire and self._max_duration_reached(elapsed):
|
||||
logger.info("Max recording length reached (%.0fs), auto-stopping",
|
||||
self._max_recording_seconds)
|
||||
should_fire = True
|
||||
|
||||
if should_fire:
|
||||
with self._lock:
|
||||
cb = self._on_silence_stop
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue