fix: persona uses settings output_language, matching the reply directive

The persona prompt was built from the raw OUTPUT_LANGUAGE env while the
reply-language directive read the settings-web UI value (config JSON), so
changing the language in the settings page was honoured by the directive
but ignored by the persona, leaving them contradicting each other.

Add _resolve_output_language() as the single source of truth (config wins
over env) and feed the same resolved value to both build_system_prompt()
and reply_language_directive(). Update docs/llm_contexts.md to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
javis-bot
2026-06-16 19:47:26 +09:00
parent b3088dd75f
commit 7870a76314
3 changed files with 99 additions and 4 deletions

View File

@@ -840,6 +840,21 @@ def _extra_config(key: str, default=""):
return default
def _resolve_output_language() -> Optional[str]:
"""Single source of truth for the locked reply language.
Precedence: the settings-web UI value (config JSON) wins over the compose
``OUTPUT_LANGUAGE`` env so changing the language in the settings page takes
effect. Returns None/empty when neither is set (multilingual default).
Both the persona prompt and the reply-language directive MUST read from
here. Resolving the two independently let the persona use the env var while
the directive used the config value, so a settings-UI change rewrote the
reply directive but left the persona contradicting it.
"""
return _extra_config("output_language", "") or os.environ.get("OUTPUT_LANGUAGE")
_SITE_TOKEN_MAP = {
"네이버": "naver", "naver": "naver",
"구글": "google", "google": "google",
@@ -1681,7 +1696,12 @@ def run_reply_engine(db: "Database", cfg, tts: Optional[Any],
action_plan = strip_memory_directives(action_plan)
_assistant_name = str(getattr(cfg, "wake_word", "jarvis") or "jarvis").strip().capitalize()
_persona_prompt = build_system_prompt(_assistant_name, os.environ.get("OUTPUT_LANGUAGE"))
# Resolve once so the persona and the reply-language directive agree: the
# settings-UI value wins over the compose OUTPUT_LANGUAGE env (see
# _resolve_output_language). Building the persona from the raw env var while
# the directive used the config value made the two contradict each other.
_output_language = _resolve_output_language()
_persona_prompt = build_system_prompt(_assistant_name, _output_language)
def _build_initial_system_message() -> str:
guidance = [_persona_prompt.strip()]
@@ -1697,9 +1717,10 @@ def run_reply_engine(db: "Database", cfg, tts: Optional[Any],
# it primacy over the persona's "use the user's language" lines — a tail
# instruction loses to those when the query itself is in another language.
# Settings-UI value (config) wins over the compose OUTPUT_LANGUAGE env so
# changing the language in the settings page actually takes effect.
# changing the language in the settings page actually takes effect. Same
# resolved value feeds the persona above, so they can't diverge.
_lang_directive = reply_language_directive(
_extra_config("output_language", "") or os.environ.get("OUTPUT_LANGUAGE"),
_output_language,
getattr(cfg, "tts_engine", "piper"),
)
if _lang_directive: