diff --git a/tui_gateway/methods_config_set.py b/tui_gateway/methods_config_set.py index dedc012ae0..4c3721f0b5 100644 --- a/tui_gateway/methods_config_set.py +++ b/tui_gateway/methods_config_set.py @@ -419,32 +419,34 @@ def _set_cwd(rid, params, key, value, session): @_cfgset_guarded -def _set_prompt_like(rid, params, key, value, session): - cfg = _load_cfg_raw() # write-back round-trip ("prompt" saves cfg) - resp = {"key": key, "value": value} - if key == "prompt": - if value == "clear": - cfg.pop("custom_prompt", None) - resp["value"] = "" - else: - cfg["custom_prompt"] = value - _save_cfg(cfg) - elif key == "personality": - pname, new_prompt = _validate_personality(str(value or ""), cfg) - # Persists via hermes_cli.personality (single owner), never the user-owned system prompt. - from hermes_cli.personality import persist_personality - persist_personality(pname) - resp["value"] = str(value or "none") - history_reset, info = _apply_personality_to_session(params.get("session_id", ""), session, new_prompt, pname) - resp["history_reset"] = history_reset - if info is not None: - resp["info"] = info +def _set_prompt(rid, params, key, value, session): + cfg = _load_cfg_raw() # write-back round-trip + if value == "clear": + cfg.pop("custom_prompt", None) else: - _write_config_key(f"display.{key}", value) - if key == "skin": # every surface repaints; sync the watcher baseline (no re-broadcast) - _broadcast_global_event("skin.changed", resolve_skin()) - _note_skin_broadcast() - return _ok(rid, resp) + cfg["custom_prompt"] = value + _save_cfg(cfg) + return _kv(rid, key, "" if value == "clear" else value) + + +@_cfgset_guarded +def _set_personality(rid, params, key, value, session): + pname, new_prompt = _validate_personality(str(value or ""), _load_cfg_raw()) + # Persists via hermes_cli.personality (single owner), never the user-owned system prompt. + from hermes_cli.personality import persist_personality + persist_personality(pname) + history_reset, info = _apply_personality_to_session(params.get("session_id", ""), session, new_prompt, pname) + return _kv(rid, key, str(value or "none"), history_reset=history_reset, + **({"info": info} if info is not None else {})) + + +@_cfgset_guarded +def _set_skin(rid, params, key, value, session): + _write_config_key("display.skin", value) + # Every surface repaints; sync the watcher baseline so the poll loop doesn't re-broadcast. + _broadcast_global_event("skin.changed", resolve_skin()) + _note_skin_broadcast() + return _kv(rid, key, value) def _set_display_toggle(rid, params, key, value, session): @@ -464,7 +466,7 @@ _CONFIG_SETTERS = { "density": _set_display_bool, "battery": _set_display_bool, "theme": _set_theme, "statusbar": _set_statusbar, "mouse": _set_mouse, "indicator": _set_indicator, "cwd": _set_cwd, "terminal.cwd": _set_cwd, "workdir": _set_cwd, - "prompt": _set_prompt_like, "personality": _set_prompt_like, "skin": _set_prompt_like} + "prompt": _set_prompt, "personality": _set_personality, "skin": _set_skin} @method("config.set") diff --git a/tui_gateway/methods_voice.py b/tui_gateway/methods_voice.py index d193906c17..4f146a7ee7 100644 --- a/tui_gateway/methods_voice.py +++ b/tui_gateway/methods_voice.py @@ -217,28 +217,24 @@ def _fd_barge_params(cfg: dict) -> tuple[float, int]: return mult, max(0, num(lambda v: int(float(v) * 1000), "barge_in_grace_seconds", 0.5)) -def _cut_all_tts() -> None: - """Cut streaming TTS, every fallback speak pipeline, and the file player.""" - from tools.voice_mode import stop_playback - _tts_stream_stop(user_barge=True) - with _fd_listener_lock: - for _stop, _done in _fd_speak_pipelines: - _stop.set() - stop_playback() - - def _fd_trip(phase: str) -> None: """Listener tripped: latch the interruption, cut TTS FIRST (so a stale reply can never speak), and during generation also interrupt every running turn (the ``agent.interrupt()`` seam ``session.interrupt`` uses).""" from tools.tts_streaming import mark_speech_interrupted + from tools.voice_mode import stop_playback mark_speech_interrupted() if phase == "playback": logger.debug("TTS CUT: full-duplex listener tripped during playback") else: logger.debug("full-duplex listener tripped during generation — " "interrupting running turn(s)") - _cut_all_tts() + # Cut streaming TTS, every fallback speak pipeline, and the file player. + _tts_stream_stop(user_barge=True) + with _fd_listener_lock: + for _stop, _done in _fd_speak_pipelines: + _stop.set() + stop_playback() if phase != "playback": try: for s in _running_sessions(): @@ -300,9 +296,8 @@ def _voice_status_payload(**extra) -> dict: """``{enabled, record_key, tts, **extra}``: record_key (default ``ctrl+b``) rides every voice.toggle branch so a tts toggle never resets a custom binding.""" record_key = _voice_cfg_dict().get("record_key") - record_key = str(record_key) if isinstance(record_key, str) and record_key else "ctrl+b" - return {"enabled": _voice_mode_enabled(), "record_key": record_key, "tts": _voice_tts_enabled(), - **extra} + record_key = record_key if isinstance(record_key, str) and record_key else "ctrl+b" + return {"enabled": _voice_mode_enabled(), "record_key": record_key, "tts": _voice_tts_enabled(), **extra} # ── Wake word ("Hey Hermes"): process-global detector (one mic). The first eligible transport @@ -678,8 +673,8 @@ def _(rid, params: dict) -> dict: return handler(rid, params) -# voice.record callbacks (module-level: they touch only process-global state). Each terminal -# capture event resumes the wake detector so wake-triggered and manual captures coexist. +# voice.record callbacks: each terminal capture event resumes the wake detector so wake-triggered +# and manual captures coexist. def _vr_transcript(payload: dict) -> None: _voice_emit("voice.transcript", payload) _resume_voice_wake()