victor34593993 commited on
Commit
1316064
·
verified ·
1 Parent(s): 7447936

fix(lang): pin the detected customer language explicitly (Spanish-heavy context was overriding plain mirror); None->mirror fallback

Browse files
Files changed (3) hide show
  1. app/prompts.py +25 -17
  2. tests/test_lang.py +9 -8
  3. tests/test_prompts.py +6 -4
app/prompts.py CHANGED
@@ -101,23 +101,31 @@ def build_system_prompt(
101
  channel: str = "web",
102
  extra_instructions: str = "",
103
  ) -> str:
104
- # LANGUAGE = mirror the customer, the way ChatGPT/Claude do it. We do NOT pin a
105
- # heuristically-detected language and command the model to use it: a wrong guess
106
- # (e.g. all-caps Spanish misread as Hungarian) would FORCE the wrong language.
107
- # Modern LLMs are natively multilingual and reply in the language they're
108
- # addressed in so we just instruct them to do exactly that and trust them.
109
- # (A separate, reliable script-based guard repairs only NON-Latin drift on weak
110
- # providers; see app.lang.needs_language_repair.)
111
- language_rule = (
112
- "Read the customer's most recent message and reply in EXACTLY the same "
113
- "language they wrote it in — mirror it (English->English, Spanish->Spanish, "
114
- "German->German, Arabic->Arabic, and so on). Detect the language yourself "
115
- "from what they actually wrote; do not assume. Never switch languages unless "
116
- "the customer does. Even if the store's catalog, product sheets or tool "
117
- "results are in another language, translate that information into the "
118
- "customer's language. This rule is absolute."
119
- )
120
- lang_short = "the SAME language the customer wrote in"
 
 
 
 
 
 
 
 
121
  channel_handoff = _WA_HANDOFF if channel == "whatsapp" else _WEB_HANDOFF
122
  # The merchant's own rules go HIGH in the prompt (right after the language
123
  # rule, before GROUNDING) and are framed as TOP priority that overrides the
 
101
  channel: str = "web",
102
  extra_instructions: str = "",
103
  ) -> str:
104
+ # LANGUAGE: reply in the customer's language. The store's catalog, tool results,
105
+ # brand and even these instructions are heavily Spanish, which DRAGS the model
106
+ # into Spanish even for an English customer (observed live) so a plain "mirror"
107
+ # hint is too weak. We pin the customer's language EXPLICITLY when we detected it
108
+ # (detection is upstream and now reliable: English->English, Spanish->Spanish,
109
+ # and the old all-caps-Spanish->Hungarian misfire is fixed at the detector). When
110
+ # detection is unsure (None) we fall back to "mirror" and trust the model. The
111
+ # non-Latin script guard (app.lang.needs_language_repair) is the last safety net.
112
+ if language:
113
+ language_rule = (
114
+ f"The customer is writing in {language}. Write your ENTIRE reply in "
115
+ f"{language}. The store's catalog, product sheets, tool results and even "
116
+ f"these instructions may be in a DIFFERENT language IGNORE that for your "
117
+ f"choice of language and TRANSLATE everything into {language}. Never reply "
118
+ f"in any other language and never mix languages. This rule is absolute."
119
+ )
120
+ lang_short = language
121
+ else:
122
+ language_rule = (
123
+ "Reply in EXACTLY the same language the customer wrote their last message "
124
+ "in — detect it yourself and mirror it. The store's data and these "
125
+ "instructions may be in another language; translate them into the "
126
+ "customer's language. Never switch languages unless the customer does."
127
+ )
128
+ lang_short = "the customer's language"
129
  channel_handoff = _WA_HANDOFF if channel == "whatsapp" else _WEB_HANDOFF
130
  # The merchant's own rules go HIGH in the prompt (right after the language
131
  # rule, before GROUNDING) and are framed as TOP priority that overrides the
tests/test_lang.py CHANGED
@@ -208,16 +208,17 @@ def test_prompt_forbids_emojis():
208
  assert "emoji" in build_system_prompt("X").lower()
209
 
210
 
211
- def test_prompt_mirrors_language_and_never_force_pins():
212
- # Root-cause fix: the prompt must tell the model to MIRROR the customer's
213
- # language (how capable LLMs natively work), NOT command "write everything in
214
- # <detected language>" a wrong detection (Hungarian) must never force a wrong
215
- # reply language. Even when a (wrong) language is passed, it is NOT pinned.
216
  from app.prompts import build_system_prompt
217
 
218
- low = build_system_prompt("Tienda", "húngaro (Hungarian)").lower()
219
- assert "same language" in low and "mirror" in low
220
- assert "húngaro" not in low # the (possibly wrong) detected name is never injected/forced
 
221
 
222
 
223
  def test_prompt_forbids_redirecting_customer_to_third_parties():
 
208
  assert "emoji" in build_system_prompt("X").lower()
209
 
210
 
211
+ def test_prompt_pins_detected_language_else_mirrors():
212
+ # The store context is heavily Spanish and drags the model into Spanish even for
213
+ # an English customer (observed live), so a detected language is pinned EXPLICITLY;
214
+ # when detection is unsure (None) we mirror. The Hungarian misfire is fixed at the
215
+ # DETECTOR (see test_spanish_detected), not by refusing to pin.
216
  from app.prompts import build_system_prompt
217
 
218
+ pinned = build_system_prompt("Tienda", "English").lower()
219
+ assert "english" in pinned and "entire reply" in pinned
220
+ unsure = build_system_prompt("Tienda", None).lower()
221
+ assert "same language" in unsure and "mirror" in unsure
222
 
223
 
224
  def test_prompt_forbids_redirecting_customer_to_third_parties():
tests/test_prompts.py CHANGED
@@ -9,11 +9,13 @@ def test_system_prompt_includes_rules_and_brand():
9
  # language is the prominent RULE #1
10
  assert "RULE #1" in p
11
  assert "language" in p.lower()
12
- # LANGUAGE = mirror the customer (like ChatGPT). A (possibly wrong) detected
13
- # language is NEVER force-pinned into the prompt that was the Hungarian bug.
 
14
  pinned = build_system_prompt("X", language="portugués de Portugal (pt-PT)")
15
- assert "pt-PT" not in pinned
16
- assert "same language" in pinned.lower() and "mirror" in pinned.lower()
 
17
  # anti-hallucination grounding
18
  assert "invent" in p.lower()
19
  # order verification (email + order number / postal code)
 
9
  # language is the prominent RULE #1
10
  assert "RULE #1" in p
11
  assert "language" in p.lower()
12
+ # A DETECTED language is pinned explicitly (the Spanish-heavy context otherwise
13
+ # drags the model into Spanish even for an English customer). The Hungarian bug
14
+ # is fixed at the DETECTOR, not by refusing to pin.
15
  pinned = build_system_prompt("X", language="portugués de Portugal (pt-PT)")
16
+ assert "pt-PT" in pinned
17
+ # when detection is unsure (None) we fall back to mirroring
18
+ assert "mirror" in build_system_prompt("X", language=None).lower()
19
  # anti-hallucination grounding
20
  assert "invent" in p.lower()
21
  # order verification (email + order number / postal code)