Add an optional OUTPUT_LANGUAGE env var that forces every reply into a single language. When set, output_language_directive() injects a "respond only in <language>" instruction (also forbidding other scripts) into the chat loop's system prompt, next to the existing TTS English-only lock. Empty (default) keeps the multilingual "reply in the user's language" behaviour, so upstream is unaffected. For the Korean-only deployment this also suppresses the occasional trailing CJK/Hanja fragment qwen2.5:3b leaks on free-form chit-chat. - system_prompt.py: language-agnostic output_language_directive() helper - engine.py: read OUTPUT_LANGUAGE, append directive in _build_initial_system_message - docker-compose.yml + .env.example: document/pass the new var - docs/llm_contexts.md: note the new gating on the main reply context - tests: cover unset/set/agnostic/whitespace cases
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
"""Tests for the unified persona system prompt.
|
|
|
|
The persona should match the user's configured wake word so renaming the
|
|
wake word to e.g. "Friday" produces a butler named Friday, not one still
|
|
hardcoded to Jarvis.
|
|
"""
|
|
|
|
from jarvis.system_prompt import build_system_prompt, output_language_directive
|
|
|
|
|
|
class TestBuildSystemPrompt:
|
|
def test_default_name_is_jarvis(self):
|
|
prompt = build_system_prompt()
|
|
assert "named Jarvis" in prompt
|
|
|
|
def test_custom_name_replaces_jarvis(self):
|
|
prompt = build_system_prompt("Friday")
|
|
assert "named Friday" in prompt
|
|
assert "named Jarvis" not in prompt
|
|
|
|
def test_lowercase_wake_word_is_capitalised(self):
|
|
prompt = build_system_prompt("friday".capitalize())
|
|
assert "named Friday" in prompt
|
|
|
|
def test_blank_name_falls_back_to_jarvis(self):
|
|
assert "named Jarvis" in build_system_prompt("")
|
|
assert "named Jarvis" in build_system_prompt(" ")
|
|
assert "named Jarvis" in build_system_prompt(None) # type: ignore[arg-type]
|
|
|
|
|
|
class TestOutputLanguageDirective:
|
|
"""A deployment may lock replies to a single language via OUTPUT_LANGUAGE.
|
|
|
|
Unset (the default) must keep the assistant's multilingual behaviour of
|
|
replying in the user's own language, so the helper returns None and no
|
|
directive is injected.
|
|
"""
|
|
|
|
def test_unset_returns_none(self):
|
|
assert output_language_directive(None) is None
|
|
assert output_language_directive("") is None
|
|
assert output_language_directive(" ") is None
|
|
|
|
def test_set_language_is_named_and_exclusive(self):
|
|
directive = output_language_directive("Korean")
|
|
assert directive is not None
|
|
assert "Korean" in directive
|
|
# Must force exclusivity, not merely prefer the language.
|
|
assert "only" in directive.lower()
|
|
|
|
def test_language_agnostic(self):
|
|
# The helper takes any language string — no hardcoded single language.
|
|
assert "French" in (output_language_directive("French") or "")
|
|
assert "日本語" in (output_language_directive("日本語") or "")
|
|
|
|
def test_strips_surrounding_whitespace(self):
|
|
directive = output_language_directive(" Korean ")
|
|
assert directive is not None
|
|
assert "Korean" in directive
|
|
assert " Korean" not in directive
|