action_parser.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import re
  2. from openhands.controller.action_parser import ActionParser
  3. from openhands.events.action import (
  4. Action,
  5. AgentFinishAction,
  6. CmdRunAction,
  7. IPythonRunCellAction,
  8. MessageAction,
  9. )
  10. class CodeActSWEActionParserFinish(ActionParser):
  11. """Parser action:
  12. - AgentFinishAction() - end the interaction
  13. """
  14. def __init__(
  15. self,
  16. ):
  17. self.finish_command = None
  18. def check_condition(self, action_str: str) -> bool:
  19. self.finish_command = re.search(r'<finish>.*</finish>', action_str, re.DOTALL)
  20. return self.finish_command is not None
  21. def parse(self, action_str: str) -> Action:
  22. assert (
  23. self.finish_command is not None
  24. ), 'self.finish_command should not be None when parse is called'
  25. thought = action_str.replace(self.finish_command.group(0), '').strip()
  26. return AgentFinishAction(thought=thought)
  27. class CodeActSWEActionParserCmdRun(ActionParser):
  28. """Parser action:
  29. - CmdRunAction(command) - bash command to run
  30. - AgentFinishAction() - end the interaction
  31. """
  32. def __init__(
  33. self,
  34. ):
  35. self.bash_command = None
  36. def check_condition(self, action_str: str) -> bool:
  37. self.bash_command = re.search(
  38. r'<execute_bash>(.*?)</execute_bash>', action_str, re.DOTALL
  39. )
  40. return self.bash_command is not None
  41. def parse(self, action_str: str) -> Action:
  42. assert (
  43. self.bash_command is not None
  44. ), 'self.bash_command should not be None when parse is called'
  45. thought = action_str.replace(self.bash_command.group(0), '').strip()
  46. # a command was found
  47. command_group = self.bash_command.group(1).strip()
  48. if command_group.strip() == 'exit':
  49. return AgentFinishAction()
  50. return CmdRunAction(command=command_group, thought=thought)
  51. class CodeActSWEActionParserIPythonRunCell(ActionParser):
  52. """Parser action:
  53. - IPythonRunCellAction(code) - IPython code to run
  54. """
  55. def __init__(
  56. self,
  57. ):
  58. self.python_code = None
  59. self.jupyter_kernel_init_code: str = 'from agentskills import *'
  60. def check_condition(self, action_str: str) -> bool:
  61. self.python_code = re.search(
  62. r'<execute_ipython>(.*?)</execute_ipython>', action_str, re.DOTALL
  63. )
  64. return self.python_code is not None
  65. def parse(self, action_str: str) -> Action:
  66. assert (
  67. self.python_code is not None
  68. ), 'self.python_code should not be None when parse is called'
  69. code_group = self.python_code.group(1).strip()
  70. thought = action_str.replace(self.python_code.group(0), '').strip()
  71. return IPythonRunCellAction(
  72. code=code_group,
  73. thought=thought,
  74. kernel_init_code=self.jupyter_kernel_init_code,
  75. )
  76. class CodeActSWEActionParserMessage(ActionParser):
  77. """Parser action:
  78. - MessageAction(content) - Message action to run (e.g. ask for clarification)
  79. """
  80. def __init__(
  81. self,
  82. ):
  83. pass
  84. def check_condition(self, action_str: str) -> bool:
  85. # We assume the LLM is GOOD enough that when it returns pure natural language
  86. # it wants to talk to the user
  87. return True
  88. def parse(self, action_str: str) -> Action:
  89. return MessageAction(content=action_str, wait_for_response=True)