From 5c1c76230bec5f02f628cadc9a8cae3d7f9c25f6 Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Sun, 24 Mar 2024 01:42:37 -0500 Subject: [PATCH] fix codeact agent to make it work --- agenthub/codeact_agent/__init__.py | 147 ++++++++++++++++------------- 1 file changed, 81 insertions(+), 66 deletions(-) diff --git a/agenthub/codeact_agent/__init__.py b/agenthub/codeact_agent/__init__.py index 829627d94de5..6e97e8761a4f 100644 --- a/agenthub/codeact_agent/__init__.py +++ b/agenthub/codeact_agent/__init__.py @@ -4,10 +4,29 @@ from termcolor import colored from typing import List, Dict -from opendevin.agent import Agent, Message, Role -from opendevin.lib.event import Event -from opendevin.lib.command_manager import CommandManager +from opendevin.agent import Agent from opendevin.sandbox.sandbox import DockerInteractive +from opendevin.state import State +from opendevin.action import ( + Action, + CmdRunAction, + CmdKillAction, + BrowseURLAction, + FileReadAction, + FileWriteAction, + AgentRecallAction, + AgentThinkAction, + AgentEchoAction, + AgentFinishAction, +) +from opendevin.observation import ( + Observation, + CmdOutputObservation, + UserMessageObservation, + AgentMessageObservation, + BrowserOutputObservation, +) + assert ( "OPENAI_API_KEY" in os.environ @@ -54,9 +73,7 @@ class CodeActAgent(Agent): def __init__( self, instruction: str, - workspace_dir: str, - model_name: str, - max_steps: int = 100 + model_name: str ) -> None: """ Initializes a new instance of the CodeActAgent class. @@ -65,69 +82,67 @@ def __init__( - instruction (str): The instruction for the agent to execute. - max_steps (int): The maximum number of steps to run the agent. """ - super().__init__(instruction, workspace_dir, model_name, max_steps) - self._history = [Message(Role.SYSTEM, SYSTEM_MESSAGE)] - self._history.append(Message(Role.USER, instruction)) - self.env = DockerInteractive(workspace_dir=workspace_dir) + super().__init__(instruction, model_name) + self.messages = [ + {"role": "system", "content": SYSTEM_MESSAGE}, + {"role": "user", "content": instruction}, + ] print(colored("===USER:===\n" + instruction, "green")) - def _history_to_messages(self) -> List[Dict]: - return [message.to_dict() for message in self._history] - - def run(self) -> None: - """ - Starts the execution of the assigned instruction. This method should - be implemented by subclasses to define the specific execution logic. - """ - for _ in range(self.max_steps): - response = completion( - messages=self._history_to_messages(), - model=self.model_name, - stop=[""], - temperature=0.0, - seed=42, - ) - action = parse_response(response) - self._history.append(Message(Role.ASSISTANT, action)) - print(colored("===ASSISTANT:===\n" + action, "yellow")) - - command = re.search(r"(.*)", action, re.DOTALL) - if command is not None: - # a command was found - command_group = command.group(1) - if command_group.strip() == "exit": - print(colored("Exit received. Exiting...", "red")) - break - # execute the code - # TODO: does exit_code get loaded into Message? - exit_code, observation = self.env.execute(command_group) - self._history.append(Message(Role.ASSISTANT, observation)) - print(colored("===ENV OBSERVATION:===\n" + observation, "blue")) - else: - # we could provide a error message for the model to continue similar to - # https://github.com/xingyaoww/mint-bench/blob/main/mint/envs/general_env.py#L18-L23 - observation = INVALID_INPUT_MESSAGE - self._history.append(Message(Role.ASSISTANT, observation)) - print(colored("===ENV OBSERVATION:===\n" + observation, "blue")) - - self.env.close() - - def chat(self, message: str) -> None: - """ - Optional method for interactive communication with the agent during its execution. Implementations - can use this method to modify the agent's behavior or state based on chat inputs. + def step(self, state: State) -> None: + updated_info = state.updated_info + + if updated_info: + + for item in updated_info: + if isinstance(item, Action): + assert isinstance(item, (CmdRunAction, AgentEchoAction)), "Expecting CmdRunAction or AgentEchoAction for Action" + + elif isinstance(item, AgentMessageObservation): # warning message from itself + self.messages.append({"role": "user", "content": item.content}) + print(colored("===USER:===\n" + item.content, "green")) + + elif isinstance(item, CmdOutputObservation): + content = "OBSERVATION:\n" + item.content + content += f"\n[Command {item.command_id} finished with exit code {item.exit_code}]]" + self.messages.append({"role": "user", "content": content}) + print(colored("===ENV OBSERVATION:===\n" + content, "blue")) + + else: + raise NotImplementedError(f"Unknown observation type: {item}") + + response = completion( + messages=self.messages, + model=self.model_name, + stop=[""], + temperature=0.0, + seed=42, + ) + action = parse_response(response) + self.messages.append({"role": "assistant", "content": action}) + print(colored("===ASSISTANT:===\n" + action, "yellow")) + + command = re.search(r"(.*)", action, re.DOTALL) + if command is not None: + # a command was found + command_group = command.group(1) + if command_group.strip() == "exit": + print(colored("Exit received. Exiting...", "red")) + return AgentFinishAction() + return CmdRunAction(command = command_group) + # # execute the code + # # TODO: does exit_code get loaded into Message? + # exit_code, observation = self.env.execute(command_group) + # self._history.append(Message(Role.ASSISTANT, observation)) + # print(colored("===ENV OBSERVATION:===\n" + observation, "blue")) + else: + # we could provide a error message for the model to continue similar to + # https://github.com/xingyaoww/mint-bench/blob/main/mint/envs/general_env.py#L18-L23 + # observation = INVALID_INPUT_MESSAGE + # self._history.append(Message(Role.ASSISTANT, observation)) + # print(colored("===ENV OBSERVATION:===\n" + observation, "blue")) + return AgentEchoAction(content=INVALID_INPUT_MESSAGE) # warning message to itself - Parameters: - - message (str): The chat message or command. - """ - raise NotImplementedError - - # TODO: implement these abstract methods - def add_event(self, event: Event) -> None: - raise NotImplementedError("Implement this abstract method") - - def step(self, cmd_mgr: CommandManager) -> Event: - raise NotImplementedError("Implement this abstract method") def search_memory(self, query: str) -> List[str]: raise NotImplementedError("Implement this abstract method")