@@ -107,19 +107,73 @@ def test_profile_rename_event_prompt_i18n_is_complete_and_first_person():
107107
108108 zh_label , zh_text = render_profile_rename_event_context ("zh-CN" , "旧角色" , "新角色" )
109109 assert zh_label == "我的改名记录"
110- assert "我以前的档案名 " in zh_text
110+ assert "我曾用名 " in zh_text
111111 assert "旧角色" in zh_text
112112 assert "新角色" in zh_text
113113 assert "只代表改名前的历史称呼" not in zh_text
114114
115115 en_label , en_text = render_profile_rename_event_context ("en" , "Old" , "New" )
116116 assert en_label == "My Profile Rename Record"
117- assert "My previous profile name " in en_text
117+ assert "formerly known as " in en_text
118118 assert "Old" in en_text
119119 assert "New" in en_text
120120 assert "historical name before the rename" not in en_text
121121
122122
123+ @pytest .mark .unit
124+ def test_profile_rename_event_master_is_person_neutral ():
125+ """主人改名记录进的是猫娘 persona 的 master section,读者是猫娘、
126+ 改名的是用户。第一人称会让猫娘误以为是自己改名,所以这里去掉人称、
127+ 用中性陈述,既不能出现「我」也不带「你」。"""
128+ from config .prompts .prompts_memory import (
129+ PROFILE_RENAME_EVENT_FIELD_MASTER ,
130+ PROFILE_RENAME_EVENT_TEXT_MASTER ,
131+ render_profile_rename_event_context ,
132+ )
133+
134+ expected_langs = {"zh" , "zh-TW" , "en" , "ja" , "ko" , "ru" , "es" , "pt" }
135+ assert set (PROFILE_RENAME_EVENT_FIELD_MASTER ) == expected_langs
136+ assert set (PROFILE_RENAME_EVENT_TEXT_MASTER ) == expected_langs
137+
138+ zh_label , zh_text = render_profile_rename_event_context ("zh-CN" , "旧名" , "新名" , entity = "master" )
139+ assert zh_label == "改名记录"
140+ assert "旧名" in zh_text and "新名" in zh_text
141+ # 去人称:既无第一人称「我」也无第二人称「你」。
142+ assert "我" not in zh_text
143+ assert "你" not in zh_text
144+
145+ en_label , en_text = render_profile_rename_event_context ("en" , "Old" , "New" , entity = "master" )
146+ assert en_label == "Profile Rename Record"
147+ assert "Old" in en_text and "New" in en_text
148+ assert "My " not in en_text and "Your " not in en_text
149+
150+ # 缺省(neko)仍是第一人称,主人变体不影响默认行为。
151+ _ , neko_text = render_profile_rename_event_context ("zh-CN" , "旧名" , "新名" )
152+ assert "我曾用名" in neko_text
153+
154+
155+ @pytest .mark .unit
156+ def test_master_effective_payload_rename_context_is_person_neutral (monkeypatch ):
157+ monkeypatch .setattr ("utils.language_utils.get_global_language_full" , lambda : "zh-CN" )
158+ from utils .config_manager import _build_effective_character_payload
159+
160+ payload = {
161+ "档案名" : "新主人名" ,
162+ "_reserved" : {
163+ "ai_context" : {
164+ "rename_events" : [
165+ {"type" : "profile_rename" , "old_name" : "旧主人名" , "new_name" : "新主人名" },
166+ ]
167+ }
168+ },
169+ }
170+ effective = _build_effective_character_payload (payload , entity = "master" )
171+ context = effective ["__ai_context.profile_rename_events" ]
172+ assert "旧主人名" in context and "新主人名" in context
173+ assert "我" not in context
174+ assert "你" not in context
175+
176+
123177@pytest .mark .unit
124178def test_profile_rename_event_uses_collision_safe_synthetic_key (monkeypatch ):
125179 monkeypatch .setattr ("utils.language_utils.get_global_language_full" , lambda : "zh-CN" )
@@ -150,7 +204,7 @@ def test_profile_rename_event_uses_collision_safe_synthetic_key(monkeypatch):
150204 assert effective ["我的改名记录" ] == "用户自己写的字段"
151205 hidden_context = effective ["__ai_context.profile_rename_events" ]
152206 assert "我的改名记录" in hidden_context
153- assert "我以前的档案名 " in hidden_context
207+ assert "我曾用名 " in hidden_context
154208 assert "旧角色" in hidden_context
155209 assert "临时角色" in hidden_context
156210 assert "新角色" in hidden_context
@@ -164,7 +218,7 @@ def test_profile_rename_event_uses_collision_safe_synthetic_key(monkeypatch):
164218 for key , value in effective_with_internal_collision .items ()
165219 if key .startswith ("__ai_context.profile_rename_events." )
166220 ]
167- assert any ("我以前的档案名 " in str (value ) for value in collision_values )
221+ assert any ("我曾用名 " in str (value ) for value in collision_values )
168222
169223
170224@pytest .mark .unit
@@ -436,14 +490,15 @@ async def _noop_any(*args, **kwargs):
436490 _ , _ , _ , effective_character_data , _ , _ , _ , _ , _ = cm .get_character_data ()
437491 hidden_context = effective_character_data ["新角色" ]["__ai_context.profile_rename_events" ]
438492 assert "我的改名记录" in hidden_context
439- assert "我以前的档案名 " in hidden_context
493+ assert "我曾用名 " in hidden_context
440494 assert "旧角色" in hidden_context
441495 assert "新角色" in hidden_context
442496 from memory .persona import PersonaManager
443497 persona_md = PersonaManager ().render_persona_markdown ("新角色" )
444- assert "__ai_context.profile_rename_events" in persona_md
498+ # 合成字段的内部裸键不能泄漏进渲染给模型的 persona 文本,只保留本地化标签。
499+ assert "__ai_context.profile_rename_events" not in persona_md
445500 assert "我的改名记录" in persona_md
446- assert "我以前的档案名 " in persona_md
501+ assert "我曾用名 " in persona_md
447502 assert "旧角色" in persona_md
448503 assert "新角色" in persona_md
449504 assert not (Path (cm .memory_dir ) / "旧角色" ).exists ()
@@ -509,15 +564,19 @@ async def _noop_any(*args, **kwargs):
509564
510565 _ , _ , master_basic_config , _ , _ , _ , _ , _ , _ = cm .get_character_data ()
511566 hidden_context = master_basic_config ["__ai_context.profile_rename_events" ]
512- assert "我的改名记录" in hidden_context
513- assert "我以前的档案名" in hidden_context
567+ # 主人改名记录进的是猫娘 persona 的 master section,去掉人称用中性陈述,
568+ # 既不能第一人称「我」(否则猫娘会以为是自己改了名),也不带第二人称「你」。
569+ assert "改名记录" in hidden_context
570+ assert "我" not in hidden_context
571+ assert "你" not in hidden_context
514572 assert old_master_name in hidden_context
515573 assert "新主人" in hidden_context
516574
517575 from memory .persona import PersonaManager
518576 persona_md = PersonaManager ().render_persona_markdown (current_catgirl )
519- assert "__ai_context.profile_rename_events" in persona_md
520- assert "我的改名记录" in persona_md
577+ # 同上:裸键不泄漏,且主人段无人称。
578+ assert "__ai_context.profile_rename_events" not in persona_md
579+ assert "改名记录" in persona_md
521580 assert old_master_name in persona_md
522581 assert "新主人" in persona_md
523582
0 commit comments