test_codeact_agent.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from unittest.mock import Mock
  2. import pytest
  3. from openhands.agenthub.codeact_agent.codeact_agent import CodeActAgent
  4. from openhands.core.config import AgentConfig, LLMConfig
  5. from openhands.core.message import TextContent
  6. from openhands.events.observation.commands import (
  7. CmdOutputObservation,
  8. IPythonRunCellObservation,
  9. )
  10. from openhands.events.observation.delegate import AgentDelegateObservation
  11. from openhands.events.observation.error import ErrorObservation
  12. from openhands.llm.llm import LLM
  13. @pytest.fixture
  14. def agent() -> CodeActAgent:
  15. agent = CodeActAgent(llm=LLM(LLMConfig()), config=AgentConfig())
  16. agent.llm = Mock()
  17. agent.llm.config = Mock()
  18. agent.llm.config.max_message_chars = 100
  19. return agent
  20. def test_cmd_output_observation_message(agent: CodeActAgent):
  21. agent.config.function_calling = False
  22. obs = CmdOutputObservation(
  23. command='echo hello', content='Command output', command_id=1, exit_code=0
  24. )
  25. results = agent.get_observation_message(obs, tool_call_id_to_message={})
  26. assert len(results) == 1
  27. result = results[0]
  28. assert result is not None
  29. assert result.role == 'user'
  30. assert len(result.content) == 1
  31. assert isinstance(result.content[0], TextContent)
  32. assert 'Command output' in result.content[0].text
  33. assert 'Command finished with exit code 0' in result.content[0].text
  34. def test_ipython_run_cell_observation_message(agent: CodeActAgent):
  35. agent.config.function_calling = False
  36. obs = IPythonRunCellObservation(
  37. code='plt.plot()',
  38. content='IPython output\n![image](data:image/png;base64,ABC123)',
  39. )
  40. results = agent.get_observation_message(obs, tool_call_id_to_message={})
  41. assert len(results) == 1
  42. result = results[0]
  43. assert result is not None
  44. assert result.role == 'user'
  45. assert len(result.content) == 1
  46. assert isinstance(result.content[0], TextContent)
  47. assert 'IPython output' in result.content[0].text
  48. assert (
  49. '![image](data:image/png;base64, ...) already displayed to user'
  50. in result.content[0].text
  51. )
  52. assert 'ABC123' not in result.content[0].text
  53. def test_agent_delegate_observation_message(agent: CodeActAgent):
  54. agent.config.function_calling = False
  55. obs = AgentDelegateObservation(
  56. content='Content', outputs={'content': 'Delegated agent output'}
  57. )
  58. results = agent.get_observation_message(obs, tool_call_id_to_message={})
  59. assert len(results) == 1
  60. result = results[0]
  61. assert result is not None
  62. assert result.role == 'user'
  63. assert len(result.content) == 1
  64. assert isinstance(result.content[0], TextContent)
  65. assert 'Delegated agent output' in result.content[0].text
  66. def test_error_observation_message(agent: CodeActAgent):
  67. agent.config.function_calling = False
  68. obs = ErrorObservation('Error message')
  69. results = agent.get_observation_message(obs, tool_call_id_to_message={})
  70. assert len(results) == 1
  71. result = results[0]
  72. assert result is not None
  73. assert result.role == 'user'
  74. assert len(result.content) == 1
  75. assert isinstance(result.content[0], TextContent)
  76. assert 'Error message' in result.content[0].text
  77. assert 'Error occurred in processing last action' in result.content[0].text
  78. def test_unknown_observation_message(agent: CodeActAgent):
  79. obs = Mock()
  80. with pytest.raises(ValueError, match='Unknown observation type'):
  81. agent.get_observation_message(obs, tool_call_id_to_message={})