"""Tests for agency_swarm.utils.files module. Tests the get_external_caller_directory() function which resolves the directory of the first caller outside the agency_swarm package. This is used to resolve relative paths like "./instructions.md" or "./tools" against the user's module file. """ import os import subprocess import sys import textwrap from pathlib import Path from agency_swarm.utils.files import _get_package_root, get_external_caller_directory class TestGetExternalCallerDirectory: """Tests for get_external_caller_directory().""" def test_returns_directory_when_called_from_external_file(self, tmp_path: Path): """When called from user code, returns the directory of that user file.""" # Create a user script that imports and calls get_external_caller_directory user_dir = tmp_path / "my_agency" user_dir.mkdir() user_script = user_dir / "create_agent.py" user_script.write_text( textwrap.dedent(""" from agency_swarm.utils.files import get_external_caller_directory result = get_external_caller_directory() print(result) """) ) # Execute the user script and capture output result = subprocess.run( [sys.executable, str(user_script)], capture_output=True, text=True, cwd=str(tmp_path), ) assert result.returncode == 0, f"Script failed: {result.stderr}" output_path = result.stdout.strip() assert output_path == str(user_dir) def test_agent_instructions_resolve_relative_to_agent_file(self, tmp_path: Path): """ Real use case: Agent created with instructions="./instructions.md" should load instructions from the agent's directory, not CWD. """ # Create directory structure mimicking user's project agent_dir = tmp_path / "agents" / "ceo" agent_dir.mkdir(parents=True) # Create instructions file in agent directory instructions_file = agent_dir / "instructions.md" instructions_file.write_text("You are the CEO agent. Lead with vision.") # Create user's agent file agent_script = agent_dir / "ceo_agent.py" agent_script.write_text( textwrap.dedent(""" import sys # Add src to path for agency_swarm import sys.path.insert(0, sys.argv[1]) from agency_swarm import Agent agent = Agent( name="CEO", instructions="./instructions.md", model="gpt-5.4-mini", ) print(agent.instructions) """) ) # Execute from a DIFFERENT directory (not the agent's directory) # This proves paths resolve relative to file location, not CWD src_path = str(Path(__file__).parent.parent.parent / "src") result = subprocess.run( [sys.executable, str(agent_script), src_path], capture_output=True, text=True, cwd=str(tmp_path), # CWD is parent, not agent_dir ) assert result.returncode == 0, f"Script failed: {result.stderr}" assert "You are the CEO agent" in result.stdout def test_agent_tools_folder_resolves_relative_to_agent_file(self, tmp_path: Path): """ Real use case: Agent with tools_folder="./tools" should load tools from the agent's tools subdirectory. """ # Create directory structure agent_dir = tmp_path / "agents" / "researcher" tools_dir = agent_dir / "tools" tools_dir.mkdir(parents=True) # Create a tool file tool_file = tools_dir / "search_tool.py" tool_file.write_text( textwrap.dedent(""" from agents import function_tool @function_tool def search_web(query: str) -> str: \"\"\"Search the web for information.\"\"\" return f"Results for: {query}" """) ) # Create user's agent file agent_script = agent_dir / "researcher.py" agent_script.write_text( textwrap.dedent(""" import sys sys.path.insert(0, sys.argv[1]) from agency_swarm import Agent agent = Agent( name="Researcher", instructions="Research things", tools_folder="./tools", model="gpt-5.4-mini", ) tool_names = [t.name for t in agent.tools] print(",".join(tool_names)) """) ) src_path = str(Path(__file__).parent.parent.parent / "src") result = subprocess.run( [sys.executable, str(agent_script), src_path], capture_output=True, text=True, cwd=str(tmp_path), # Different CWD ) assert result.returncode == 0, f"Script failed: {result.stderr}" assert "search_web" in result.stdout def test_agency_shared_instructions_resolve_relative_to_agency_file(self, tmp_path: Path): """ Real use case: Agency with shared_instructions="agency_manifesto.md" should load from the agency's directory. """ agency_dir = tmp_path / "my_agency" agency_dir.mkdir() # Create manifesto file manifesto_file = agency_dir / "agency_manifesto.md" manifesto_file.write_text("Our mission: Be helpful and accurate.") # Create agency script agency_script = agency_dir / "agency.py" agency_script.write_text( textwrap.dedent(""" import sys sys.path.insert(0, sys.argv[1]) from agency_swarm import Agency, Agent ceo = Agent(name="CEO", instructions="Lead", model="gpt-5.4-mini") agency = Agency(ceo, shared_instructions="agency_manifesto.md") print(agency.shared_instructions) """) ) src_path = str(Path(__file__).parent.parent.parent / "src") result = subprocess.run( [sys.executable, str(agency_script), src_path], capture_output=True, text=True, cwd=str(tmp_path), ) assert result.returncode == 0, f"Script failed: {result.stderr}" assert "Our mission:" in result.stdout def test_fallback_to_cwd_when_no_external_caller(self): """When no file-backed external caller exists, returns os.getcwd().""" # This tests the fallback when called from within the package # or when the stack has no external callers result = get_external_caller_directory() # Since this test file IS outside agency_swarm package, # it should return THIS file's directory expected = str(Path(__file__).parent) assert result == expected def test_fallback_to_cwd_when_package_root_not_found(self): """When internal_package doesn't exist, returns os.getcwd().""" result = get_external_caller_directory(internal_package="nonexistent_package_xyz") assert result == os.getcwd() class TestGetPackageRoot: """Tests for _get_package_root() helper function.""" def test_returns_path_for_valid_package(self): """Returns the package root path for a valid package.""" result = _get_package_root("agency_swarm") assert result is not None assert result.name == "agency_swarm" assert result.is_dir() def test_returns_none_for_invalid_package(self): """Returns None for a package that doesn't exist.""" result = _get_package_root("this_package_does_not_exist_xyz") assert result is None def test_returns_none_for_builtin_module(self): """Returns None for built-in modules without __file__.""" # sys is a built-in module that might not have __file__ # We test by providing a package name that imports but has no file result = _get_package_root("builtins") assert result is None def test_caches_results(self): """Results are cached via lru_cache.""" # Clear the cache first _get_package_root.cache_clear() # Call twice result1 = _get_package_root("agency_swarm") result2 = _get_package_root("agency_swarm") # Results should be identical (same object due to cache) assert result1 is result2 # Check cache info shows hit cache_info = _get_package_root.cache_info() assert cache_info.hits >= 1 class TestSpecialFilenameFiltering: """Tests for filtering special Python filenames like , .""" def test_code_from_exec_falls_back_to_cwd(self, tmp_path: Path): """ Code executed via exec() has filename '' and should be filtered. The function should skip such frames and find the real caller or fall back. """ # Create a script that uses exec() to call get_external_caller_directory test_script = tmp_path / "exec_test.py" script_content = """\ import sys sys.path.insert(0, sys.argv[1]) from agency_swarm.utils.files import get_external_caller_directory # This code will be executed with filename='' code = ''' result = get_external_caller_directory() print(result) ''' exec(code) """ test_script.write_text(script_content) src_path = str(Path(__file__).parent.parent.parent / "src") result = subprocess.run( [sys.executable, str(test_script), src_path], capture_output=True, text=True, cwd=str(tmp_path), ) assert result.returncode == 0, f"Script failed: {result.stderr}" output_path = result.stdout.strip() # Should return the outer script's directory (tmp_path), not error out # because the frame is skipped and the outer exec_test.py is found assert output_path == str(tmp_path) def test_handles_mixed_stack_with_special_frames(self, tmp_path: Path): """ When the call stack has both special frames and real file frames, the function should skip special frames and find the first real external caller. """ # Create nested structure where inner code uses eval/exec outer_dir = tmp_path / "outer" outer_dir.mkdir() outer_script = outer_dir / "outer.py" outer_script.write_text( textwrap.dedent(""" import sys sys.path.insert(0, sys.argv[1]) def call_via_exec(): from agency_swarm.utils.files import get_external_caller_directory # This exec adds a frame to the stack code = "result = get_external_caller_directory(); print(result)" exec(code) call_via_exec() """) ) src_path = str(Path(__file__).parent.parent.parent / "src") result = subprocess.run( [sys.executable, str(outer_script), src_path], capture_output=True, text=True, cwd=str(tmp_path), ) assert result.returncode == 0, f"Script failed: {result.stderr}" output_path = result.stdout.strip() # Should find outer.py as the external caller (skipping ) assert output_path == str(outer_dir)