Files
hermes-webui/tests/test_5145_steer_default.py
nesquena-hermesandRod Boev b931ae2f9b fix(settings): reconcile #5145 rename+steer-flip onto master's #5170 mirror
Rebase PR #5162 (rename busy_input_mode -> default_message_mode; flip the
default from 'queue' to 'steer') onto current origin/master WITHOUT dropping
the shipped #5170 localStorage persistence mirror.

Rename the mirror machinery to the new setting name for consistency:
  _BUSY_INPUT_MODES        -> _DEFAULT_MESSAGE_MODES        (values unchanged)
  _normalizeBusyInputMode  -> _normalizeDefaultMessageMode  (fallback now 'steer')
  _persistBusyInputMode    -> _persistDefaultMessageMode
  _readPersistedBusyInputMode -> _readPersistedDefaultMessageMode
  window._busyInputMode    -> window._defaultMessageMode (+ renamed exports)

localStorage: write the new 'hermes-default-message-mode' key; read it with a
fallback to the legacy 'hermes-busy-input-mode' key so an existing user's
persisted preference survives the rename.

Preserve #5170 behavior at every mirror site under the new names:
  - boot success  -> window._defaultMessageMode=_persistDefaultMessageMode(...)
  - boot FAILURE  -> window._defaultMessageMode=_readPersistedDefaultMessageMode()
    (NOT a hardcoded 'steer' — a saved 'interrupt'/'queue' must still apply when
    the server is unreachable; do not regress #5167/#5132)
  - preferences autosave, settings-panel load, and _applySavedSettingsUi all
    persist through _persistDefaultMessageMode(...)

Tests updated for the rename while keeping the persistence-behavior assertions
(test_1062, test_5145, test_5167); test_5167 gains explicit guards that the
load-failure path reads the persisted pref and never hardcodes a literal mode,
plus autosave/panel-load mirror-write coverage.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-07-02 05:44:48 +00:00

130 lines
6.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Focused regression coverage for #5145 busy-input defaults."""
import re
from pathlib import Path
ROOT = Path(__file__).parent.parent
CONFIG_PY = (ROOT / "api" / "config.py").read_text(encoding="utf-8")
BOOT_JS = (ROOT / "static" / "boot.js").read_text(encoding="utf-8")
PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8")
INDEX_HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
I18N_JS = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
LOCALE_KEYS = (
"en",
"it",
"ja",
"ru",
"es",
"de",
"zh",
"'zh-Hant'",
"pt",
"ko",
"fr",
"tr",
"pl",
"vi",
)
def _locale_block(locale_key):
escaped_keys = [re.escape(key) for key in LOCALE_KEYS]
next_keys = "|".join(key for key in escaped_keys if key != re.escape(locale_key))
pattern = rf"^ {re.escape(locale_key)}: \{{(?P<body>.*?)(?=^ (?:{next_keys}): \{{|\n\}};)"
match = re.search(pattern, I18N_JS, re.MULTILINE | re.DOTALL)
assert match, f"missing {locale_key} locale block"
return match.group("body")
def _default_message_mode_label(locale_key):
block = _locale_block(locale_key)
match = re.search(r"settings_label_default_message_mode: '([^']+)'", block)
assert match, f"missing default message mode label for {locale_key}"
return match.group(1)
def _default_message_mode_steer_option(locale_key):
block = _locale_block(locale_key)
match = re.search(r"settings_default_message_mode_steer: '([^']+)'", block)
assert match, f"missing default message mode steer option for {locale_key}"
return match.group(1)
def _default_message_mode_description(locale_key):
block = _locale_block(locale_key)
match = re.search(r"settings_desc_default_message_mode: ([\"'])((?:\\.|(?!\1).)*)\1", block)
assert match, f"missing default message mode description for {locale_key}"
return match.group(2)
def test_backend_default_resolves_to_steer():
assert '"default_message_mode": "steer"' in CONFIG_PY
def test_boot_defaults_resolve_to_steer():
# Success path routes through the #5170 persistence mirror; the resolved
# value still defaults to 'steer' because _normalizeDefaultMessageMode()
# returns 'steer' for a missing/invalid value.
assert "window._defaultMessageMode=_persistDefaultMessageMode(s.default_message_mode||s.busy_input_mode)" in BOOT_JS
assert "return _DEFAULT_MESSAGE_MODES.includes(mode)?mode:'steer';" in BOOT_JS
# Load-FAILURE path re-reads the persisted mirror (never a hardcoded literal),
# so a saved preference survives an unreachable server (#5167/#5170). With no
# persisted value the normalize fallback still yields 'steer'.
assert "window._defaultMessageMode=_readPersistedDefaultMessageMode()" in BOOT_JS
assert "window._defaultMessageMode='steer'" not in BOOT_JS
def test_settings_panel_fallbacks_resolve_to_steer():
assert "String(settings.default_message_mode||settings.busy_input_mode||'steer')" in PANELS_JS
assert "['queue','interrupt','steer'].includes(val)?val:'steer'" in PANELS_JS
# _applySavedSettingsUi routes through the #5170 mirror; the ||'steer' tail
# keeps steer as the resolved default when the helper is unavailable.
assert "_persistDefaultMessageMode(body.default_message_mode||body.busy_input_mode)" in PANELS_JS
assert "body.default_message_mode||body.busy_input_mode||'steer'" in PANELS_JS
assert "const defaultMessageMode=($('settingsDefaultMessageMode')||{}).value||'steer'" in PANELS_JS
def test_busy_input_label_changes_without_key_or_id_drift():
assert 'id="settingsDefaultMessageMode"' in INDEX_HTML
assert 'data-i18n="settings_label_default_message_mode">Default message mode' in INDEX_HTML
assert _default_message_mode_label("en") == "Default message mode"
assert I18N_JS.count("settings_label_default_message_mode: 'Default message mode'") == 1
def test_busy_input_labels_stay_in_their_locale_blocks():
assert _default_message_mode_label("it") == "Modalità messaggio predefinita"
assert _default_message_mode_label("ja") == "既定のメッセージモード"
assert _default_message_mode_label("ru") == "Режим сообщений по умолчанию"
assert _default_message_mode_label("es") == "Modo de mensaje predeterminado"
assert _default_message_mode_label("de") == "Standard-Nachrichtenmodus"
assert _default_message_mode_label("zh") == "默认消息模式"
assert _default_message_mode_label("'zh-Hant'") == "預設訊息模式"
assert _default_message_mode_label("pt") == "Modo de mensagem padrão"
assert _default_message_mode_label("ko") == "기본 메시지 모드"
assert _default_message_mode_label("fr") == "Mode de message par défaut"
assert _default_message_mode_label("tr") == "Varsayılan mesaj modu"
assert _default_message_mode_label("pl") == "Domyślny tryb wiadomości"
assert _default_message_mode_label("vi") == "Chế độ tin nhắn mặc định"
def test_russian_steer_option_keeps_mid_turn_meaning():
assert _default_message_mode_steer_option("ru") == "Steer (коррекция в середине хода)"
def test_localized_descriptions_keep_draft_restore_meaning():
expected_restore_phrases = {
"it": "bozza viene ripristinata",
"ja": "下書きが復元",
"ru": "черновик восстанавливается",
"es": "borrador se restaura",
"de": "Entwurf wiederhergestellt",
"zh": "恢复草稿",
"'zh-Hant'": "恢復草稿",
"pt": "rascunho é restaurado",
"ko": "초안이 복원",
"fr": "brouillon est restauré",
"tr": "taslak geri yüklenir",
"pl": "szkic zostaje przywrócony",
"vi": "bản nháp sẽ được khôi phục",
}
for locale_key, restore_phrase in expected_restore_phrases.items():
assert restore_phrase in _default_message_mode_description(locale_key), (
f"{locale_key} description must describe restoring the draft when Steer is unavailable"
)