feat(brain): add OUTPUT_LANGUAGE reply-language lock
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
This commit is contained in:
@@ -5,10 +5,11 @@ Handles memory enrichment, tool planning and execution.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from ..utils.redact import redact
|
||||
from ..system_prompt import build_system_prompt
|
||||
from ..system_prompt import build_system_prompt, output_language_directive
|
||||
from ..tools.registry import run_tool_with_retries, generate_tools_description, generate_tools_json_schema, BUILTIN_TOOLS
|
||||
from ..tools.builtin.stop import STOP_SIGNAL
|
||||
from ..debug import debug_log
|
||||
@@ -1441,6 +1442,14 @@ def run_reply_engine(db: "Database", cfg, tts: Optional[Any],
|
||||
"Always respond in English regardless of the language the user speaks in."
|
||||
)
|
||||
|
||||
# Deployment-level output-language lock (OUTPUT_LANGUAGE). When set,
|
||||
# force every reply into that single language and forbid stray
|
||||
# characters from other scripts. Empty (default) keeps the
|
||||
# multilingual behaviour of replying in the user's own language.
|
||||
_lang_directive = output_language_directive(os.environ.get("OUTPUT_LANGUAGE"))
|
||||
if _lang_directive:
|
||||
guidance.append(_lang_directive)
|
||||
|
||||
if warm_profile_block:
|
||||
# Pre-query, query-agnostic user context. Lives OUTSIDE the
|
||||
# conversation-history section because it isn't a history
|
||||
|
||||
@@ -6,6 +6,8 @@ who renames the wake word (e.g. "Friday") gets a butler with the matching
|
||||
name rather than a persona hardcoded to "Jarvis".
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
_SYSTEM_PROMPT_TEMPLATE: str = (
|
||||
"Persona: you are a British butler named {name} — polite, composed, quietly amused, and "
|
||||
"quietly enjoying yourself. Default voice is dry, witty, and lightly sarcastic: you notice "
|
||||
@@ -87,3 +89,26 @@ def build_system_prompt(assistant_name: str = "Jarvis") -> str:
|
||||
"""
|
||||
name = (assistant_name or "Jarvis").strip() or "Jarvis"
|
||||
return _SYSTEM_PROMPT_TEMPLATE.format(name=name)
|
||||
|
||||
|
||||
def output_language_directive(language: Optional[str]) -> Optional[str]:
|
||||
"""Return a 'respond only in <language>' instruction, or None when unset.
|
||||
|
||||
Deployments that serve a single language set ``OUTPUT_LANGUAGE`` (read by
|
||||
the reply engine). When it is empty/None the assistant keeps its default
|
||||
multilingual behaviour of replying in whatever language the user wrote in,
|
||||
so this returns ``None`` and no directive is injected.
|
||||
|
||||
The instruction is language-agnostic — it names whatever language string it
|
||||
is given — and forbids mixing in other scripts. That exclusivity also
|
||||
suppresses the occasional trailing CJK/Hanja fragment some small models
|
||||
leak on free-form chit-chat.
|
||||
"""
|
||||
lang = (language or "").strip()
|
||||
if not lang:
|
||||
return None
|
||||
return (
|
||||
f"Always respond only in {lang}, regardless of the language the user "
|
||||
f"writes in. Do not mix in words, characters, or punctuation from any "
|
||||
f"other language or script."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user