test_create_agent_template.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. """Tests for create_agent_template utility."""
  2. from pathlib import Path
  3. from unittest.mock import patch
  4. import pytest
  5. from agency_swarm.utils.create_agent_template import create_agent_template
  6. class TestCreateAgentTemplate:
  7. """Test the create_agent_template function."""
  8. def test_create_basic_agent_template(self, tmp_path: Path) -> None:
  9. """Test creating a basic agent template with minimal parameters."""
  10. agent_name = "Test Agent"
  11. result = create_agent_template(agent_name=agent_name, path=str(tmp_path))
  12. assert result is True
  13. # Check folder structure (now uses underscores)
  14. agent_folder = tmp_path / "test_agent"
  15. assert agent_folder.exists()
  16. assert agent_folder.is_dir()
  17. # Check required files
  18. assert (agent_folder / "__init__.py").exists()
  19. assert (agent_folder / "test_agent.py").exists()
  20. assert (agent_folder / "instructions.md").exists()
  21. # Check required directories
  22. assert (agent_folder / "tools").exists()
  23. assert (agent_folder / "files").exists()
  24. assert (agent_folder / "tools" / "__init__.py").exists()
  25. assert (agent_folder / "tools" / "ExampleTool.py").exists()
  26. def test_create_agent_template_without_description(self, tmp_path: Path) -> None:
  27. """Test creating agent template without description - should use default placeholder."""
  28. agent_name = "Simple Agent"
  29. assert create_agent_template(agent_name=agent_name, path=str(tmp_path)) is True
  30. agent_folder = tmp_path / "simple_agent"
  31. agent_file = agent_folder / "simple_agent.py"
  32. agent_content = agent_file.read_text(encoding="utf-8")
  33. # Should NOT have description line
  34. assert "description=" not in agent_content
  35. assert f'name="{agent_name}"' in agent_content
  36. assert 'instructions="./instructions.md"' in agent_content
  37. # Instructions file should have structured template with placeholder
  38. instructions_file = agent_folder / "instructions.md"
  39. instructions_content = instructions_file.read_text(encoding="utf-8")
  40. assert "# Role" in instructions_content
  41. assert "**[insert role" in instructions_content
  42. assert "# Goals" in instructions_content
  43. assert "# Process" in instructions_content
  44. assert "# Output Format" in instructions_content
  45. assert "# Additional Notes" in instructions_content
  46. def test_agent_file_content_structure(self, tmp_path: Path) -> None:
  47. """Test that generated agent file has correct v1.x structure."""
  48. agent_name = "Data Processor"
  49. agent_description = "Processes and analyzes data"
  50. assert (
  51. create_agent_template(
  52. agent_name=agent_name,
  53. agent_description=agent_description,
  54. path=str(tmp_path),
  55. )
  56. is True
  57. )
  58. agent_folder = tmp_path / "data_processor"
  59. agent_file = agent_folder / "data_processor.py"
  60. agent_content = agent_file.read_text(encoding="utf-8")
  61. # Check v1.x imports and structure
  62. assert "from agency_swarm import Agent, ModelSettings" in agent_content
  63. assert "data_processor = Agent(" in agent_content
  64. assert f'name="{agent_name}"' in agent_content
  65. assert f'description="{agent_description}"' in agent_content
  66. assert 'instructions="./instructions.md"' in agent_content
  67. assert 'files_folder="./files"' in agent_content
  68. assert 'tools_folder="./tools"' in agent_content
  69. assert 'model="gpt-5.4"' in agent_content # Updated default model
  70. assert "ModelSettings(" in agent_content
  71. # gpt-5.4 is a reasoning model - no temperature
  72. assert "temperature=" not in agent_content
  73. def test_instructions_file_content(self, tmp_path: Path) -> None:
  74. """Test that instructions file has correct structured template content."""
  75. agent_name = "Research Assistant"
  76. agent_description = "Helps with research tasks"
  77. assert (
  78. create_agent_template(
  79. agent_name=agent_name,
  80. agent_description=agent_description,
  81. path=str(tmp_path),
  82. )
  83. is True
  84. )
  85. agent_folder = tmp_path / "research_assistant"
  86. instructions_file = agent_folder / "instructions.md"
  87. instructions_content = instructions_file.read_text(encoding="utf-8")
  88. # Should have structured template sections
  89. assert "# Role" in instructions_content
  90. assert "You are" in instructions_content
  91. assert agent_description in instructions_content
  92. assert "# Goals" in instructions_content
  93. assert "# Process" in instructions_content
  94. assert "# Output Format" in instructions_content
  95. assert "# Additional Notes" in instructions_content
  96. def test_custom_instructions(self, tmp_path: Path) -> None:
  97. """Test creating agent with custom instructions."""
  98. agent_name = "Custom Agent"
  99. agent_description = "Custom description"
  100. custom_instructions = "These are custom instructions for the agent."
  101. assert (
  102. create_agent_template(
  103. agent_name=agent_name,
  104. agent_description=agent_description,
  105. path=str(tmp_path),
  106. instructions=custom_instructions,
  107. )
  108. is True
  109. )
  110. agent_folder = tmp_path / "custom_agent"
  111. instructions_file = agent_folder / "instructions.md"
  112. instructions_content = instructions_file.read_text(encoding="utf-8")
  113. assert instructions_content == custom_instructions
  114. def test_custom_instructions_with_description(self, tmp_path: Path) -> None:
  115. """Test creating agent with custom instructions and description."""
  116. agent_name = "Custom Agent"
  117. agent_description = "Custom description"
  118. custom_instructions = "You are a specialized agent. Follow these rules: 1. Be precise 2. Be helpful"
  119. assert (
  120. create_agent_template(
  121. agent_name=agent_name,
  122. agent_description=agent_description,
  123. instructions=custom_instructions,
  124. path=str(tmp_path),
  125. )
  126. is True
  127. )
  128. agent_folder = tmp_path / "custom_agent"
  129. # Agent file should have description
  130. agent_file = agent_folder / "custom_agent.py"
  131. agent_content = agent_file.read_text(encoding="utf-8")
  132. assert f'description="{agent_description}"' in agent_content
  133. # Instructions file should have custom content (not auto-generated)
  134. instructions_file = agent_folder / "instructions.md"
  135. instructions_content = instructions_file.read_text(encoding="utf-8")
  136. assert instructions_content == custom_instructions
  137. def test_custom_instructions_without_description(self, tmp_path: Path) -> None:
  138. """Test creating agent with custom instructions but no description."""
  139. agent_name = "Instruction Agent"
  140. custom_instructions = "You are a specialized agent with custom instructions."
  141. assert (
  142. create_agent_template(agent_name=agent_name, instructions=custom_instructions, path=str(tmp_path)) is True
  143. )
  144. agent_folder = tmp_path / "instruction_agent"
  145. # Agent file should NOT have description
  146. agent_file = agent_folder / "instruction_agent.py"
  147. agent_content = agent_file.read_text(encoding="utf-8")
  148. assert "description=" not in agent_content
  149. # Instructions file should have custom content
  150. instructions_file = agent_folder / "instructions.md"
  151. instructions_content = instructions_file.read_text(encoding="utf-8")
  152. assert instructions_content == custom_instructions
  153. def test_use_txt_extension(self, tmp_path: Path) -> None:
  154. """Test creating agent with .txt instructions file."""
  155. agent_name = "Text Agent"
  156. agent_description = "Uses txt files"
  157. assert (
  158. create_agent_template(
  159. agent_name=agent_name,
  160. agent_description=agent_description,
  161. path=str(tmp_path),
  162. use_txt=True,
  163. )
  164. is True
  165. )
  166. agent_folder = tmp_path / "text_agent"
  167. # Should create .txt file instead of .md
  168. assert (agent_folder / "instructions.txt").exists()
  169. assert not (agent_folder / "instructions.md").exists()
  170. # Agent file should reference .txt extension
  171. agent_file = agent_folder / "text_agent.py"
  172. agent_content = agent_file.read_text(encoding="utf-8")
  173. assert 'instructions="./instructions.txt"' in agent_content
  174. def test_without_example_tool(self, tmp_path: Path) -> None:
  175. """Test creating agent without example tool."""
  176. agent_name = "No Tool Agent"
  177. agent_description = "Agent without example tool"
  178. assert (
  179. create_agent_template(
  180. agent_name=agent_name,
  181. agent_description=agent_description,
  182. path=str(tmp_path),
  183. include_example_tool=False,
  184. )
  185. is True
  186. )
  187. agent_folder = tmp_path / "no_tool_agent"
  188. # Should not create ExampleTool.py
  189. assert not (agent_folder / "tools" / "ExampleTool.py").exists()
  190. # But should still create tools folder and __init__.py
  191. assert (agent_folder / "tools").exists()
  192. assert (agent_folder / "tools" / "__init__.py").exists()
  193. def test_init_file_content(self, tmp_path: Path) -> None:
  194. """Test that __init__.py file has correct imports."""
  195. agent_name = "Import Test Agent"
  196. agent_description = "Test imports"
  197. assert (
  198. create_agent_template(
  199. agent_name=agent_name,
  200. agent_description=agent_description,
  201. path=str(tmp_path),
  202. )
  203. is True
  204. )
  205. agent_folder = tmp_path / "import_test_agent"
  206. init_file = agent_folder / "__init__.py"
  207. init_content = init_file.read_text(encoding="utf-8")
  208. assert "from .import_test_agent import import_test_agent" in init_content
  209. def test_example_tool_content(self, tmp_path: Path) -> None:
  210. """Test that ExampleTool.py has correct v1.x structure."""
  211. agent_name = "Tool Test Agent"
  212. agent_description = "Test tool generation"
  213. assert (
  214. create_agent_template(
  215. agent_name=agent_name,
  216. agent_description=agent_description,
  217. path=str(tmp_path),
  218. )
  219. is True
  220. )
  221. agent_folder = tmp_path / "tool_test_agent"
  222. tool_file = agent_folder / "tools" / "ExampleTool.py"
  223. tool_content = tool_file.read_text(encoding="utf-8")
  224. # Check v1.x tool structure
  225. assert "from agency_swarm.tools import BaseTool" in tool_content
  226. assert "from pydantic import Field" in tool_content
  227. assert "from dotenv import load_dotenv" in tool_content
  228. assert "load_dotenv()" in tool_content
  229. assert "class ExampleTool(BaseTool):" in tool_content
  230. assert "def run(self):" in tool_content
  231. assert 'if __name__ == "__main__":' in tool_content
  232. def test_folder_already_exists_error(self, tmp_path: Path) -> None:
  233. """Test that creating agent in existing folder raises error."""
  234. agent_name = "Existing Agent"
  235. agent_description = "Test existing folder"
  236. # Create the folder first
  237. (tmp_path / "existing_agent").mkdir()
  238. # Should raise exception
  239. with pytest.raises(FileExistsError, match="Folder already exists"):
  240. create_agent_template(agent_name=agent_name, agent_description=agent_description, path=str(tmp_path))
  241. def test_agent_name_normalization(self, tmp_path: Path) -> None:
  242. """Test that agent names with spaces are normalized correctly."""
  243. agent_name = "Complex Agent Name With Spaces"
  244. agent_description = "Test name normalization"
  245. assert (
  246. create_agent_template(
  247. agent_name=agent_name,
  248. agent_description=agent_description,
  249. path=str(tmp_path),
  250. )
  251. is True
  252. )
  253. # Should create folder with underscores
  254. agent_folder = tmp_path / "complex_agent_name_with_spaces"
  255. assert agent_folder.exists()
  256. # Check that agent variable is correct in files
  257. agent_file = agent_folder / "complex_agent_name_with_spaces.py"
  258. agent_content = agent_file.read_text(encoding="utf-8")
  259. assert "complex_agent_name_with_spaces = Agent(" in agent_content
  260. init_file = agent_folder / "__init__.py"
  261. init_content = init_file.read_text(encoding="utf-8")
  262. assert "from .complex_agent_name_with_spaces import complex_agent_name_with_spaces" in init_content
  263. def test_agent_name_with_dots_preserves_version_digits(self, tmp_path: Path) -> None:
  264. """Agent names containing dots should normalize to underscores without dropping digits."""
  265. agent_name = "Versioned Agent 1.2"
  266. assert create_agent_template(agent_name=agent_name, path=str(tmp_path)) is True
  267. agent_folder = tmp_path / "versioned_agent_1_2"
  268. assert agent_folder.exists()
  269. assert (agent_folder / "versioned_agent_1_2.py").exists()
  270. init_content = (agent_folder / "__init__.py").read_text(encoding="utf-8")
  271. assert "from .versioned_agent_1_2 import versioned_agent_1_2" in init_content
  272. @patch("builtins.input")
  273. def test_interactive_input(self, mock_input, tmp_path: Path) -> None:
  274. """Test interactive input when name not provided."""
  275. mock_input.return_value = "Interactive Agent"
  276. assert create_agent_template(path=str(tmp_path)) is True
  277. # Should create agent with input name
  278. agent_folder = tmp_path / "interactive_agent"
  279. assert agent_folder.exists()
  280. agent_file = agent_folder / "interactive_agent.py"
  281. agent_content = agent_file.read_text(encoding="utf-8")
  282. assert 'name="Interactive Agent"' in agent_content
  283. # Should NOT have description since we don't prompt for it anymore
  284. assert "description=" not in agent_content