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