Browse Source

refactor browsing agent response parse (#2366)

* refactor browsing

* add comments

* change file name

* Rename resposne_parser.py to response_parser.py

* Fixed typos

* Typo fix

---------

Co-authored-by: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
Yufan Song 1 year ago
parent
commit
c6951eb6c1
2 changed files with 92 additions and 33 deletions
  1. 4 33
      agenthub/browsing_agent/browsing_agent.py
  2. 88 0
      agenthub/browsing_agent/response_parser.py

+ 4 - 33
agenthub/browsing_agent/browsing_agent.py

@@ -1,9 +1,9 @@
-import ast
 import os
 
 from browsergym.core.action.highlevel import HighLevelActionSet
 from browsergym.utils.obs import flatten_axtree_to_str
 
+from agenthub.browsing_agent.response_parser import BrowsingResponseParser
 from opendevin.controller.agent import Agent
 from opendevin.controller.state.state import State
 from opendevin.core.logger import opendevin_logger as logger
@@ -42,6 +42,7 @@ class BrowsingAgent(Agent):
 
     sandbox_plugins: list[PluginRequirement] = []
     runtime_tools: list[RuntimeTool] = [RuntimeTool.BROWSER]
+    response_parser = BrowsingResponseParser()
 
     def __init__(
         self,
@@ -75,31 +76,6 @@ class BrowsingAgent(Agent):
         self.cost_accumulator = 0
         self.error_accumulator = 0
 
-    def parse_response(self, response: str) -> Action:
-        if '```' not in response:
-            # unexpected response format, message back to user
-            action_str = f'send_msg_to_user("""{response}""")'
-            return BrowseInteractiveAction(
-                browser_actions=action_str,
-                thought=response,
-                browsergym_send_msg_to_user=response,
-            )
-        thought = response.split('```')[0].strip()
-        action_str = response.split('```')[1].strip()
-        # handle send message to user function call in BrowserGym
-        msg_content = ''
-        for sub_action in action_str.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
-
-        return BrowseInteractiveAction(
-            browser_actions=action_str,
-            thought=thought,
-            browsergym_send_msg_to_user=msg_content,
-        )
-
     def step(self, state: State) -> Action:
         """
         Performs one step using the Browsing Agent.
@@ -216,19 +192,14 @@ In order to accomplish my goal I need to send the information asked back to the
 """
             prompt += concise_instruction
         messages.append({'role': 'user', 'content': prompt})
+        logger.info(prompt)
         response = self.llm.completion(
             messages=messages,
             temperature=0.0,
             stop=[')```', ')\n```'],
         )
         self.log_cost(response)
-        action_resp = response['choices'][0]['message']['content'].strip()
-        if not action_resp.endswith('```'):
-            action_resp = action_resp + ')```'
-
-        logger.info(prompt)
-        logger.info(action_resp)
-        return self.parse_response(action_resp)
+        return self.response_parser.parse(response)
 
     def search_memory(self, query: str) -> list[str]:
         raise NotImplementedError('Implement this abstract method')

+ 88 - 0
agenthub/browsing_agent/response_parser.py

@@ -0,0 +1,88 @@
+import ast
+
+from opendevin.controller.action_parser import ActionParser, ResponseParser
+from opendevin.core.logger import opendevin_logger as logger
+from opendevin.events.action import (
+    Action,
+    BrowseInteractiveAction,
+)
+
+
+class BrowsingResponseParser(ResponseParser):
+    def __init__(
+        self,
+    ):
+        # Need to pay attention to the item order in self.action_parsers
+        self.action_parsers = [BrowsingActionParserMessage()]
+        self.default_parser = BrowsingActionParserBrowseInteractive()
+
+    def parse(self, response: str) -> Action:
+        action_str = self.parse_response(response)
+        return self.parse_action(action_str)
+
+    def parse_response(self, response) -> str:
+        action_str = response['choices'][0]['message']['content'].strip()
+        if not action_str.endswith('```'):
+            action_str = action_str + ')```'
+        logger.info(action_str)
+        return action_str
+
+    def parse_action(self, action_str: str) -> Action:
+        for action_parser in self.action_parsers:
+            if action_parser.check_condition(action_str):
+                return action_parser.parse(action_str)
+        return self.default_parser.parse(action_str)
+
+
+class BrowsingActionParserMessage(ActionParser):
+    """
+    Parser action:
+        - BrowseInteractiveAction(browser_actions) - unexpected response format, message back to user
+    """
+
+    def __init__(
+        self,
+    ):
+        pass
+
+    def check_condition(self, action_str: str) -> bool:
+        return '```' not in action_str
+
+    def parse(self, action_str: str) -> Action:
+        msg = f'send_msg_to_user("""{action_str}""")'
+        return BrowseInteractiveAction(
+            browser_actions=msg,
+            thought=action_str,
+            browsergym_send_msg_to_user=action_str,
+        )
+
+
+class BrowsingActionParserBrowseInteractive(ActionParser):
+    """
+    Parser action:
+        - BrowseInteractiveAction(browser_actions) - handle send message to user function call in BrowserGym
+    """
+
+    def __init__(
+        self,
+    ):
+        pass
+
+    def check_condition(self, action_str: str) -> bool:
+        return True
+
+    def parse(self, action_str: str) -> Action:
+        thought = action_str.split('```')[0].strip()
+        action_str = action_str.split('```')[1].strip()
+        msg_content = ''
+        for sub_action in action_str.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
+
+        return BrowseInteractiveAction(
+            browser_actions=action_str,
+            thought=thought,
+            browsergym_send_msg_to_user=msg_content,
+        )