test_response_parsing.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import pytest
  2. from openhands.agenthub.micro.agent import parse_response as parse_response_micro
  3. from openhands.agenthub.planner_agent.prompt import (
  4. parse_response as parse_response_planner,
  5. )
  6. from openhands.core.exceptions import LLMResponseError
  7. from openhands.core.utils.json import loads as custom_loads
  8. from openhands.events.action import (
  9. FileWriteAction,
  10. MessageAction,
  11. )
  12. @pytest.mark.parametrize(
  13. 'parse_response_module',
  14. [parse_response_micro, parse_response_planner],
  15. )
  16. def test_parse_single_complete_json(parse_response_module):
  17. input_response = """
  18. {
  19. "action": "message",
  20. "args": {
  21. "content": "The following typos were fixed:\\n* 'futur' -> 'future'\\n* 'imagin' -> 'imagine'\\n* 'techological' -> 'technological'\\n* 'responsability' -> 'responsibility'\\nThe corrected file is ./short_essay.txt."
  22. }
  23. }
  24. """
  25. expected = MessageAction(
  26. "The following typos were fixed:\n* 'futur' -> 'future'\n* 'imagin' -> 'imagine'\n* 'techological' -> 'technological'\n* 'responsability' -> 'responsibility'\nThe corrected file is ./short_essay.txt."
  27. )
  28. result = parse_response_module(input_response)
  29. assert result == expected
  30. @pytest.mark.parametrize(
  31. 'parse_response_module',
  32. [parse_response_micro, parse_response_planner],
  33. )
  34. def test_parse_json_with_surrounding_text(parse_response_module):
  35. input_response = """
  36. Some initial text that is not JSON formatted.
  37. {
  38. "action": "write",
  39. "args": {
  40. "path": "./updated_file.txt",
  41. "content": "Updated text content here..."
  42. }
  43. }
  44. Some trailing text that is also not JSON formatted.
  45. """
  46. expected = FileWriteAction(
  47. path='./updated_file.txt', content='Updated text content here...'
  48. )
  49. result = parse_response_module(input_response)
  50. assert result == expected
  51. @pytest.mark.parametrize(
  52. 'parse_response_module',
  53. [parse_response_micro, parse_response_planner],
  54. )
  55. def test_parse_first_of_multiple_jsons(parse_response_module):
  56. input_response = """
  57. I will firstly do
  58. {
  59. "action": "write",
  60. "args": {
  61. "path": "./short_essay.txt",
  62. "content": "Text content here..."
  63. }
  64. }
  65. Then I will continue with
  66. {
  67. "action": "think",
  68. "args": {
  69. "thought": "This should not be parsed."
  70. }
  71. }
  72. """
  73. expected = FileWriteAction(path='./short_essay.txt', content='Text content here...')
  74. result = parse_response_module(input_response)
  75. assert result == expected
  76. def test_invalid_json_raises_error():
  77. # This should fail if repair_json is able to fix this faulty JSON
  78. input_response = '{"action": "write", "args": { "path": "./short_essay.txt", "content": "Missing closing brace" }'
  79. with pytest.raises(LLMResponseError):
  80. custom_loads(input_response)
  81. def test_no_json_found():
  82. input_response = 'This is just a string with no JSON object.'
  83. with pytest.raises(LLMResponseError):
  84. custom_loads(input_response)