import sys from unittest.mock import patch import pytest from openhands.agenthub.codeact_agent.codeact_agent import CodeActAgent from openhands.core.config import AgentConfig from openhands.llm.llm import LLM # Skip all tests in this module if not running on Windows pytestmark = pytest.mark.skipif( sys.platform != 'win32', reason='Windows prompt refinement tests require Windows' ) @pytest.fixture def mock_llm(): """Create a mock LLM for testing.""" llm = LLM(config={'model': 'gpt-4', 'api_key': 'test'}) return llm @pytest.fixture def agent_config(): """Create a basic agent config for testing.""" return AgentConfig() def test_codeact_agent_system_prompt_no_bash_on_windows(mock_llm, agent_config): """Test that CodeActAgent's system prompt doesn't contain 'bash' on Windows.""" # Create a CodeActAgent instance agent = CodeActAgent(llm=mock_llm, config=agent_config) # Get the system prompt system_prompt = agent.prompt_manager.get_system_message() # Assert that 'bash' doesn't exist in the system prompt (case-insensitive) assert 'bash' not in system_prompt.lower(), ( f"System prompt contains 'bash' on Windows platform. " f"It should be replaced with 'powershell'. " f'System prompt: {system_prompt}' ) # Verify that 'powershell' exists instead (case-insensitive) assert 'powershell' in system_prompt.lower(), ( f"System prompt should contain 'powershell' on Windows platform. " f'System prompt: {system_prompt}' ) def test_codeact_agent_tool_descriptions_no_bash_on_windows(mock_llm, agent_config): """Test that CodeActAgent's tool descriptions don't contain 'bash' on Windows.""" # Create a CodeActAgent instance agent = CodeActAgent(llm=mock_llm, config=agent_config) # Get the tools tools = agent.tools # Check each tool's description and parameters for tool in tools: if tool['type'] == 'function': function_info = tool['function'] # Check function description description = function_info.get('description', '') assert 'bash' not in description.lower(), ( f"Tool '{function_info['name']}' description contains 'bash' on Windows. " f'Description: {description}' ) # Check parameter descriptions parameters = function_info.get('parameters', {}) properties = parameters.get('properties', {}) for param_name, param_info in properties.items(): param_description = param_info.get('description', '') assert 'bash' not in param_description.lower(), ( f"Tool '{function_info['name']}' parameter '{param_name}' " f"description contains 'bash' on Windows. " f'Parameter description: {param_description}' ) def test_in_context_learning_example_no_bash_on_windows(): """Test that in-context learning examples don't contain 'bash' on Windows.""" from openhands.agenthub.codeact_agent.tools.bash import create_cmd_run_tool from openhands.agenthub.codeact_agent.tools.finish import FinishTool from openhands.agenthub.codeact_agent.tools.str_replace_editor import ( create_str_replace_editor_tool, ) from openhands.llm.fn_call_converter import get_example_for_tools # Create a sample set of tools tools = [ create_cmd_run_tool(), create_str_replace_editor_tool(), FinishTool, ] # Get the in-context learning example example = get_example_for_tools(tools) # Assert that 'bash' doesn't exist in the example (case-insensitive) assert 'bash' not in example.lower(), ( f"In-context learning example contains 'bash' on Windows platform. " f"It should be replaced with 'powershell'. " f'Example: {example}' ) # Verify that 'powershell' exists instead (case-insensitive) if example: # Only check if example is not empty assert 'powershell' in example.lower(), ( f"In-context learning example should contain 'powershell' on Windows platform. " f'Example: {example}' ) def test_refine_prompt_function_works(): """Test that the refine_prompt function correctly replaces 'bash' with 'powershell'.""" from openhands.agenthub.codeact_agent.tools.bash import refine_prompt # Test basic replacement test_prompt = 'Execute a bash command to list files' refined_prompt = refine_prompt(test_prompt) assert 'bash' not in refined_prompt.lower() assert 'powershell' in refined_prompt.lower() assert refined_prompt == 'Execute a powershell command to list files' # Test multiple occurrences test_prompt = 'Use bash to run bash commands in the bash shell' refined_prompt = refine_prompt(test_prompt) assert 'bash' not in refined_prompt.lower() assert ( refined_prompt == 'Use powershell to run powershell commands in the powershell shell' ) # Test case sensitivity test_prompt = 'BASH and Bash and bash should all be replaced' refined_prompt = refine_prompt(test_prompt) assert 'bash' not in refined_prompt.lower() assert ( refined_prompt == 'powershell and powershell and powershell should all be replaced' ) # Test execute_bash tool name replacement test_prompt = 'Use the execute_bash tool to run commands' refined_prompt = refine_prompt(test_prompt) assert 'execute_bash' not in refined_prompt.lower() assert 'execute_powershell' in refined_prompt.lower() assert refined_prompt == 'Use the execute_powershell tool to run commands' # Test that words containing 'bash' but not equal to 'bash' are preserved test_prompt = 'The bashful person likes bash-like syntax' refined_prompt = refine_prompt(test_prompt) # 'bashful' should be preserved, 'bash-like' should become 'powershell-like' assert 'bashful' in refined_prompt assert 'powershell-like' in refined_prompt assert refined_prompt == 'The bashful person likes powershell-like syntax' def test_refine_prompt_function_on_non_windows(): """Test that the refine_prompt function doesn't change anything on non-Windows platforms.""" from openhands.agenthub.codeact_agent.tools.bash import refine_prompt # Mock sys.platform to simulate non-Windows with patch('openhands.agenthub.codeact_agent.tools.bash.sys.platform', 'linux'): test_prompt = 'Execute a bash command to list files' refined_prompt = refine_prompt(test_prompt) # On non-Windows, the prompt should remain unchanged assert refined_prompt == test_prompt assert 'bash' in refined_prompt.lower()