Files
javis_bot/tests/test_output_language_resolution.py
javis-bot 7870a76314 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>
2026-06-16 19:47:26 +09:00

75 lines
3.0 KiB
Python

"""The locked reply language must have a single source of truth.
Regression: the persona prompt was built from the raw ``OUTPUT_LANGUAGE`` env
while the reply-language directive read the settings-UI value (config JSON).
Changing the language in the settings page rewrote the directive but left the
persona contradicting it. ``_resolve_output_language`` is now the one resolver
both call sites use, so they cannot diverge.
"""
import pytest
@pytest.mark.unit
def test_settings_value_wins_over_env(monkeypatch, tmp_path):
from jarvis.reply.engine import _resolve_output_language
cfg_path = tmp_path / "config.json"
cfg_path.write_text('{"output_language": "Korean"}', encoding="utf-8")
monkeypatch.setenv("JARVIS_CONFIG_PATH", str(cfg_path))
monkeypatch.setenv("OUTPUT_LANGUAGE", "English")
# The settings page value must take effect over the compose env default.
assert _resolve_output_language() == "Korean"
@pytest.mark.unit
def test_env_used_when_settings_absent(monkeypatch, tmp_path):
from jarvis.reply.engine import _resolve_output_language
cfg_path = tmp_path / "config.json"
cfg_path.write_text("{}", encoding="utf-8")
monkeypatch.setenv("JARVIS_CONFIG_PATH", str(cfg_path))
monkeypatch.setenv("OUTPUT_LANGUAGE", "English")
assert _resolve_output_language() == "English"
@pytest.mark.unit
def test_unset_when_neither_configured(monkeypatch, tmp_path):
from jarvis.reply.engine import _resolve_output_language
cfg_path = tmp_path / "config.json"
cfg_path.write_text("{}", encoding="utf-8")
monkeypatch.setenv("JARVIS_CONFIG_PATH", str(cfg_path))
monkeypatch.delenv("OUTPUT_LANGUAGE", raising=False)
# Empty string or None both mean "no lock" downstream; normalise the check.
assert not _resolve_output_language()
@pytest.mark.unit
def test_persona_and_directive_agree_on_settings_value(monkeypatch, tmp_path):
"""End-to-end: the same resolved value feeds the persona and the directive,
so a settings-UI language can't be honoured by one and ignored by the other.
"""
from jarvis.reply.engine import _resolve_output_language
from jarvis.system_prompt import build_system_prompt, reply_language_directive
cfg_path = tmp_path / "config.json"
cfg_path.write_text('{"output_language": "Korean"}', encoding="utf-8")
monkeypatch.setenv("JARVIS_CONFIG_PATH", str(cfg_path))
monkeypatch.setenv("OUTPUT_LANGUAGE", "English")
lang = _resolve_output_language()
persona = build_system_prompt("Jarvis", lang)
directive = reply_language_directive(lang, "melo")
# Persona's user-language clause is rewritten to Korean, not English...
assert "in Korean" in persona
assert "in English" not in persona
# ...and the directive locks to the same Korean. (The directive may name
# English as a counter-example - "even if the user writes in English" - so
# we assert the lock target, not the mere absence of the word "English".)
assert directive is not None and "Korean" in directive