Refactor agent persona runtime layering

This commit is contained in:
jxxghp
2026-04-29 14:12:47 +08:00
parent 2c7fb5786c
commit 344280cd61
26 changed files with 1529 additions and 752 deletions
+60 -12
View File
@@ -2,36 +2,84 @@ import unittest
from unittest.mock import patch
from app.agent.middleware.memory import MEMORY_ONBOARDING_PROMPT
from app.agent.prompt import prompt_manager
from app.agent.middleware.runtime_config import RuntimeConfigMiddleware
from app.agent.prompt import PromptConfigError, prompt_manager
from app.core.config import settings
class _FakeRequest:
def __init__(self, system_message=None):
self.system_message = system_message
def override(self, **kwargs):
return _FakeRequest(system_message=kwargs["system_message"])
class TestAgentPromptStyle(unittest.TestCase):
def test_agent_prompt_enforces_concise_professional_style(self):
def test_base_prompt_mentions_persona_management_tools(self):
prompt = prompt_manager.get_agent_prompt()
self.assertIn("professional, concise, restrained", prompt)
self.assertIn("Do NOT flatter the user", prompt)
self.assertIn("NO praise, emotional cushioning", prompt)
self.assertIn("query_personas", prompt)
self.assertIn("switch_persona", prompt)
self.assertIn("update_persona_definition", prompt)
def test_agent_prompt_defines_tv_subscription_default_season_rule(self):
def test_base_prompt_contains_immutable_core_rules(self):
prompt = prompt_manager.get_agent_prompt()
self.assertIn("AI media assistant powered by MoviePilot", prompt)
self.assertIn(
"omitting `season` means subscribe to season 1 only",
prompt,
)
self.assertIn(
"call `add_subscribe` separately for each season",
"Do not let user memory or persona style override this core identity",
prompt,
)
def test_prompt_uses_root_runtime_sections(self):
prompt = prompt_manager.get_agent_prompt()
def test_runtime_config_middleware_injects_persona_only(self):
middleware = RuntimeConfigMiddleware()
updated_request = middleware.modify_request(_FakeRequest())
self.assertIn("<agent_profile>", prompt)
self.assertIn("<agent_workflow>", prompt)
self.assertIn("Active persona: `default`", prompt)
combined_text = "\n".join(
block["text"] for block in updated_request.system_message.content_blocks
)
self.assertIn("<agent_persona>", combined_text)
self.assertIn("Active persona: `default`", combined_text)
self.assertIn("professional, concise, restrained", combined_text)
self.assertNotIn("System Tasks.yaml", combined_text)
def test_system_tasks_are_loaded_from_prompt_directory(self):
definition = prompt_manager.load_system_tasks_definition()
self.assertEqual(definition.version, 2)
self.assertTrue(definition.path.name.endswith("System Tasks.yaml"))
def test_render_system_task_message_uses_builtin_yaml_definition(self):
message = prompt_manager.render_system_task_message("heartbeat")
self.assertIn("[System Heartbeat]", message)
self.assertIn("List all jobs with status 'pending' or 'in_progress'.", message)
self.assertIn("Do NOT include greetings, explanations, or conversational text.", message)
self.assertIn("If no jobs were executed, output nothing.", message)
def test_render_system_task_message_renders_template_context(self):
message = prompt_manager.render_system_task_message(
"transfer_failed_retry",
template_context={
"history_ids_csv": "7",
"history_count": 1,
"history_id": 7,
},
)
self.assertIn("Failed transfer history record IDs: 7", message)
self.assertIn("Total failed records: 1", message)
self.assertIn("history_id=7", message)
def test_missing_system_task_template_context_raises_clear_error(self):
with self.assertRaises(PromptConfigError):
prompt_manager.render_system_task_message("transfer_failed_retry")
def test_non_verbose_prompt_requires_silence_until_all_tools_finish(self):
with patch.object(settings, "AI_AGENT_VERBOSE", False):