"""U-004 tests: migrated agent personas compile into valid-shaped subagent definitions and deploy correctly. No real `claude` calls here -- see src/test_agent_e2e.py (RUN_REAL_AGENT_E2E=1) for the actual A-2 validation. Run: python3 -m unittest src.test_agent_profile -v """ import os import tempfile import unittest from src import agent_profile, schema class RenderAgentDefinitionTest(unittest.TestCase): def test_all_three_org_nodes_render(self): for org_node in agent_profile.ORG_NODES: with self.subTest(org_node=org_node): content = agent_profile.render_agent_definition(org_node) self.assertTrue(content.startswith("---\n")) self.assertIn("name: " + org_node, content) self.assertIn("memory: project", content) self.assertIn("model:", content) self.assertIn("skills:", content) self.assertIn("tools:", content) def test_validator_has_disallowed_tools_from_agents_md_contract(self): content = agent_profile.render_agent_definition("validator") self.assertIn("disallowedTools:", content) self.assertIn("- Edit", content) self.assertIn("- Write", content) self.assertIn("Bash(git commit:*)", content) def test_planner_and_coder_have_no_disallowed_tools(self): for org_node in ("planner", "coder"): content = agent_profile.render_agent_definition(org_node) self.assertNotIn("disallowedTools:", content) def test_validator_body_includes_both_soul_and_agents_md(self): content = agent_profile.render_agent_definition("validator") self.assertIn("QA Agent", content) # from SOUL.md self.assertIn("AGENTS.md — QA Profile 运行契约", content) # from AGENTS.md def test_no_leaked_feishu_secret_or_personal_path(self): for org_node in agent_profile.ORG_NODES: content = agent_profile.render_agent_definition(org_node) self.assertNotIn("MCYAbbfuEaY03ks8F45cs53qnfd", content) self.assertNotIn("/Users/yibo/Projects/lemonAI/graphagent", content) # the original told Coder to itself run this; the migrated version is # allowed to *mention* the flag only as a prohibition, not an instruction self.assertNotIn("优先使用 `claude --dangerously-skip-permissions`", content) self.assertNotIn("优先使用 claude --dangerously-skip-permissions", content) class DeployAgentDefinitionsTest(unittest.TestCase): def test_writes_three_files_into_target_claude_agents(self): with tempfile.TemporaryDirectory() as tmp: agent_profile.deploy_agent_definitions(tmp) out_dir = os.path.join(tmp, ".claude", "agents") for org_node in agent_profile.ORG_NODES: path = os.path.join(out_dir, org_node + ".md") self.assertTrue(os.path.isfile(path)) with open(path, encoding="utf-8") as f: self.assertTrue(f.read().startswith("---\n")) class RecordAgentProfilesTest(unittest.TestCase): def setUp(self): self.conn = schema.connect(":memory:") schema.create_schema(self.conn) def tearDown(self): self.conn.close() def test_inserts_one_row_per_org_node(self): agent_profile.record_agent_profiles(self.conn, "deadbeef") rows = self.conn.execute( "SELECT org_node, migrated_from_profile, current_git_commit_sha FROM agent_profile ORDER BY org_node" ).fetchall() self.assertEqual(len(rows), 3) by_node = {r[0]: r for r in rows} self.assertEqual(by_node["planner"][1], "planning") self.assertEqual(by_node["coder"][1], "code") self.assertEqual(by_node["validator"][1], "qa") for row in rows: self.assertEqual(row[2], "deadbeef") def test_validator_has_agents_file_path_others_do_not(self): agent_profile.record_agent_profiles(self.conn, "deadbeef") rows = dict( self.conn.execute("SELECT org_node, agents_file_path FROM agent_profile").fetchall() ) self.assertIsNone(rows["planner"]) self.assertIsNone(rows["coder"]) self.assertIsNotNone(rows["validator"]) def test_rerun_upserts_instead_of_duplicating(self): agent_profile.record_agent_profiles(self.conn, "sha-1") agent_profile.record_agent_profiles(self.conn, "sha-2") count = self.conn.execute("SELECT COUNT(*) FROM agent_profile").fetchone()[0] self.assertEqual(count, 3) sha = self.conn.execute( "SELECT current_git_commit_sha FROM agent_profile WHERE org_node = 'planner'" ).fetchone()[0] self.assertEqual(sha, "sha-2") if __name__ == "__main__": unittest.main()