diff --git a/openhands/agenthub/browsing_agent/response_parser.py b/openhands/agenthub/browsing_agent/response_parser.py index 6ececb9482d8..8687016c6ad7 100644 --- a/openhands/agenthub/browsing_agent/response_parser.py +++ b/openhands/agenthub/browsing_agent/response_parser.py @@ -1,4 +1,5 @@ import ast +import re from openhands.controller.action_parser import ActionParser, ResponseParser from openhands.core.logger import openhands_logger as logger @@ -24,8 +25,13 @@ def parse_response(self, response) -> str: if action_str is None: return '' action_str = action_str.strip() - if action_str and not action_str.endswith('```'): - action_str = action_str + ')```' + # Ensure action_str ends with ')```' + if action_str: + if not action_str.endswith('```'): + if action_str.endswith(')'): + action_str += '```' # prevent duplicate ending paranthesis, e.g. send_msg_to_user('Done')) + else: + action_str += ')```' # expected format logger.debug(action_str) return action_str @@ -96,9 +102,19 @@ def parse(self, action_str: str) -> Action: msg_content = '' for sub_action in browser_actions.split('\n'): if 'send_msg_to_user(' in sub_action: - tree = ast.parse(sub_action) - args = tree.body[0].value.args # type: ignore - msg_content = args[0].value + try: + tree = ast.parse(sub_action) + args = tree.body[0].value.args # type: ignore + msg_content = args[0].value + except SyntaxError: + logger.error(f'Error parsing action: {sub_action}') + # the syntax was not correct, but we can still try to get the message + # e.g. send_msg_to_user("Hello, world!") or send_msg_to_user('Hello, world!' + match = re.search(r'send_msg_to_user\((["\'])(.*?)\1\)', sub_action) + if match: + msg_content = match.group(2) + else: + msg_content = '' return BrowseInteractiveAction( browser_actions=browser_actions, diff --git a/tests/unit/test_browsing_agent_parser.py b/tests/unit/test_browsing_agent_parser.py index 011ebb6b32d9..351b8e8eaf93 100644 --- a/tests/unit/test_browsing_agent_parser.py +++ b/tests/unit/test_browsing_agent_parser.py @@ -12,10 +12,14 @@ ("click('81'", "click('81')```"), ( '"We need to search the internet\n```goto("google.com")', - '"We need to search the internet\n```goto("google.com"))```', + '"We need to search the internet\n```goto("google.com")```', ), ("```click('81'", "```click('81')```"), - ("click('81')", "click('81'))```"), + ("click('81')", "click('81')```"), + ( + "send_msg_to_user('The server might not be running or accessible. Please check the server status and try again.')", + "send_msg_to_user('The server might not be running or accessible. Please check the server status and try again.')```", + ), ], ) def test_parse_response(action_str: str, expected: str) -> None: @@ -37,6 +41,30 @@ def test_parse_response(action_str: str, expected: str) -> None: 'We need to perform a click', '', ), + ( + 'Tell the user that the city was built in 1751.\n```send_msg_to_user("Based on the results of my search, the city was built in 1751.")', + 'send_msg_to_user("Based on the results of my search, the city was built in 1751.")', + 'Tell the user that the city was built in 1751.', + 'Based on the results of my search, the city was built in 1751.', + ), + ( + 'Tell the user that the city was built in 1751.\n```send_msg_to_user("Based on the results of my search, the city was built in 1751.")```', + 'send_msg_to_user("Based on the results of my search, the city was built in 1751.")', + 'Tell the user that the city was built in 1751.', + 'Based on the results of my search, the city was built in 1751.', + ), + ( + "Tell the user that the city was built in 1751.\n```send_msg_to_user('Based on the results of my search, the city was built in 1751.')```", + "send_msg_to_user('Based on the results of my search, the city was built in 1751.')", + 'Tell the user that the city was built in 1751.', + 'Based on the results of my search, the city was built in 1751.', + ), + ( + "send_msg_to_user('The server might not be running or accessible. Please check the server status and try again.'))```", + "send_msg_to_user('The server might not be running or accessible. Please check the server status and try again.'))", + '', + 'The server might not be running or accessible. Please check the server status and try again.', + ), ], ) def test_parse_action(