fix(tui): voice mode starts OFF each launch (CLI parity)

The voice.toggle handler was persisting display.voice_enabled /
display.voice_tts to config.yaml, so a TUI session that ever turned
voice on would re-open with it already on (and the mic badge lit) on
every subsequent launch.  cli.py treats voice strictly as runtime
state: _voice_mode = False at __init__, only /voice on flips it, and
nothing writes it back to disk.

Drop the _write_config_key calls in voice.toggle on/off/tts and the
config.yaml fallback in _voice_mode_enabled / _voice_tts_enabled.
State is now env-var-only (HERMES_VOICE / HERMES_VOICE_TTS), scoped to
the live gateway subprocess — the next launch starts clean.
This commit is contained in:
0xbyt4
2026-04-24 02:06:01 +03:00
committed by Teknium
parent 2af0848f3c
commit 44a0cbe525

View File

@@ -3576,21 +3576,20 @@ def _voice_emit(event: str, payload: dict | None = None) -> None:
def _voice_mode_enabled() -> bool: def _voice_mode_enabled() -> bool:
"""Current voice-mode flag. HERMES_VOICE env var wins over config so """Current voice-mode flag (runtime-only, CLI parity).
the gateway and CLI agree when one of them was launched with an
explicit override.""" cli.py initialises ``_voice_mode = False`` at startup and only flips
env = os.environ.get("HERMES_VOICE", "").strip() it via ``/voice on``; it never reads a persisted enable bit from
if env in {"0", "1"}: config.yaml. We match that: no config lookup, env var only. This
return env == "1" avoids the TUI auto-starting in REC the next time the user opens it
return bool(_load_cfg().get("display", {}).get("voice_enabled", False)) just because they happened to enable voice in a prior session.
"""
return os.environ.get("HERMES_VOICE", "").strip() == "1"
def _voice_tts_enabled() -> bool: def _voice_tts_enabled() -> bool:
"""Whether agent replies should be spoken back via TTS.""" """Whether agent replies should be spoken back via TTS (runtime only)."""
env = os.environ.get("HERMES_VOICE_TTS", "").strip() return os.environ.get("HERMES_VOICE_TTS", "").strip() == "1"
if env in {"0", "1"}:
return env == "1"
return bool(_load_cfg().get("display", {}).get("voice_tts", False))
@method("voice.toggle") @method("voice.toggle")
@@ -3634,8 +3633,10 @@ def _(rid, params: dict) -> dict:
if action in ("on", "off"): if action in ("on", "off"):
enabled = action == "on" enabled = action == "on"
# Runtime-only flag (CLI parity) — no _write_config_key, so the
# next TUI launch starts with voice OFF instead of auto-REC from a
# persisted stale toggle.
os.environ["HERMES_VOICE"] = "1" if enabled else "0" os.environ["HERMES_VOICE"] = "1" if enabled else "0"
_write_config_key("display.voice_enabled", enabled)
if not enabled: if not enabled:
# Disabling the mode must tear the continuous loop down; the # Disabling the mode must tear the continuous loop down; the
@@ -3655,8 +3656,8 @@ def _(rid, params: dict) -> dict:
if not _voice_mode_enabled(): if not _voice_mode_enabled():
return _err(rid, 4014, "enable voice mode first: /voice on") return _err(rid, 4014, "enable voice mode first: /voice on")
new_value = not _voice_tts_enabled() new_value = not _voice_tts_enabled()
# Runtime-only flag (CLI parity) — see voice.toggle on/off above.
os.environ["HERMES_VOICE_TTS"] = "1" if new_value else "0" os.environ["HERMES_VOICE_TTS"] = "1" if new_value else "0"
_write_config_key("display.voice_tts", new_value)
return _ok(rid, {"enabled": True, "tts": new_value}) return _ok(rid, {"enabled": True, "tts": new_value})
return _err(rid, 4013, f"unknown voice action: {action}") return _err(rid, 4013, f"unknown voice action: {action}")