"""Prompt builders 在 language='en' 时返回纯 ASCII;language='zh' 时含中文(防回归)。""" from __future__ import annotations from app.agents.chat.output_rules import ( chat_output_rules, chat_output_rules_en, chat_voice_style, chat_voice_style_en, ) from app.agents.chat.personas import AGENT_NAME_EN, AGENT_NAME_ZH, agent_name from app.agents.chat.prompts_conversation import ( get_guided_conversation_prompt, get_opening_prompt, ) from app.agents.chat.prompts_profile import ( get_profile_followup_prompt, get_profile_greeting_prompt, ) from app.agents.memoir.prompts import ( get_creative_title_json_prompt, get_memoir_fidelity_facts_only_prompt, get_memoir_fidelity_system_prompt, get_narrative_json_prompt, ) from app.agents.stage_constants import ( chapter_category_display, stage_display_name, ) def _has_cjk(s: str) -> bool: return any("\u4e00" <= ch <= "\u9fff" for ch in s) # ── chat output rules ──────────────────────────────────────────────── def test_chat_output_rules_en_has_no_cjk() -> None: txt = chat_output_rules_en() assert txt.strip() assert not _has_cjk(txt) def test_chat_voice_style_en_has_no_cjk() -> None: txt = chat_voice_style_en() assert txt.strip() assert not _has_cjk(txt) def test_chat_output_rules_zh_unchanged_has_cjk() -> None: assert _has_cjk(chat_output_rules()) def test_chat_voice_style_zh_unchanged_has_cjk() -> None: assert _has_cjk(chat_voice_style()) # ── memoir narrative ──────────────────────────────────────────────── def test_memoir_fidelity_facts_only_en_branch_has_no_cjk() -> None: assert not _has_cjk(get_memoir_fidelity_facts_only_prompt(language="en")) def test_memoir_fidelity_facts_only_zh_default_has_cjk() -> None: assert _has_cjk(get_memoir_fidelity_facts_only_prompt()) def test_memoir_fidelity_system_en_branch_has_no_cjk() -> None: assert not _has_cjk(get_memoir_fidelity_system_prompt(language="en")) def test_get_narrative_json_prompt_en_has_no_cjk() -> None: out = get_narrative_json_prompt( stage="childhood", slots={"place": "the village"}, new_content="[User's oral memory this turn]\nI grew up by the river.", language="en", ) assert not _has_cjk(out) assert "paragraphs" in out def test_get_narrative_json_prompt_zh_default_has_cjk() -> None: out = get_narrative_json_prompt( stage="childhood", slots={"place": "村里"}, new_content="【本段用户口述】\n我小时候住在河边。", ) assert _has_cjk(out) # ── memoir title ──────────────────────────────────────────────────── def test_creative_title_json_prompt_en_has_no_cjk() -> None: out = get_creative_title_json_prompt( stage="childhood", emotion="warm", slots={"place": "the river"}, language="en", ) assert not _has_cjk(out) assert "title" in out def test_creative_title_json_prompt_zh_default_has_cjk() -> None: out = get_creative_title_json_prompt( stage="childhood", emotion="warm", slots={"place": "河边"}, ) assert _has_cjk(out) # ── stage / category display helpers ──────────────────────────────── def test_stage_display_name_branches() -> None: assert stage_display_name("childhood", language="en") == "Childhood" assert stage_display_name("childhood", language="zh") == "童年时光" # unknown stages pass through assert stage_display_name("unknown", language="en") == "unknown" def test_chapter_category_display_branches() -> None: assert chapter_category_display("childhood", language="en") == "Childhood & Early Years" assert chapter_category_display("childhood", language="zh") == "童年与成长背景" # ── agent brand name (interviewer identity) ───────────────────────── def test_agent_name_constants_aligned_with_brand() -> None: """中英品牌名是单一来源,prompt / UI / 兜底标题统一引用此处。""" assert AGENT_NAME_ZH == "岁月知己" assert AGENT_NAME_EN == "Life Echo" def test_agent_name_helper_handles_inputs() -> None: assert agent_name("zh") == "岁月知己" assert agent_name("en") == "Life Echo" assert agent_name("EN") == "Life Echo" assert agent_name(" en ") == "Life Echo" assert agent_name(None) == "岁月知己" # type: ignore[arg-type] assert agent_name("ja") == "岁月知己" def test_profile_greeting_prompt_introduces_life_echo_in_en() -> None: en = get_profile_greeting_prompt( ["birth_year", "occupation"], nickname="Sam", language="en" ) assert "Life Echo" in en assert "岁月知己" not in en def test_profile_greeting_prompt_keeps_chinese_brand_in_zh() -> None: zh = get_profile_greeting_prompt(["birth_year"], nickname="老王") assert "岁月知己" in zh assert "Life Echo" not in zh def test_profile_followup_prompt_introduces_life_echo_in_en() -> None: en = get_profile_followup_prompt( missing_fields=["occupation"], filled_fields={"birth_year": "1990"}, language="en", ) assert "Life Echo" in en assert "岁月知己" not in en def test_profile_followup_prompt_full_basics_branch_introduces_life_echo() -> None: en = get_profile_followup_prompt( missing_fields=[], filled_fields={ "birth_year": "1990", "birth_place": "Boston", "grew_up_place": "Boston", "occupation": "engineer", }, language="en", ) assert "Life Echo" in en assert "岁月知己" not in en def test_opening_prompt_introduces_life_echo_in_en() -> None: out = get_opening_prompt( current_stage="childhood", empty_slots_readable=["place", "people"], language="en", ) assert "Life Echo" in out assert "岁月知己" not in out def test_guided_conversation_prompt_introduces_life_echo_in_en() -> None: out = get_guided_conversation_prompt( current_stage="childhood", empty_slots=["place"], filled_slots={}, language="en", ) assert "Life Echo" in out assert "岁月知己" not in out