From 8ecc6bc49bca1ff8364be9953eb757ab7ed23de4 Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Thu, 27 Jun 2024 06:42:25 +0200 Subject: [PATCH] send messages separately, adjust summarize prompt --- agenthub/codeact_agent/codeact_agent.py | 23 ++++++++++++++++++++--- opendevin/core/main.py | 2 +- opendevin/events/action/agent.py | 11 ++++++----- opendevin/memory/prompts.py | 16 ++++++++++++++-- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/agenthub/codeact_agent/codeact_agent.py b/agenthub/codeact_agent/codeact_agent.py index ce0549ca98..8d08cff9d8 100644 --- a/agenthub/codeact_agent/codeact_agent.py +++ b/agenthub/codeact_agent/codeact_agent.py @@ -53,7 +53,7 @@ def action_to_str(action: Action) -> str: elif isinstance(action, MessageAction): return action.content elif isinstance(action, AgentSummarizeAction): - return action.summary + return action.summarized_actions return '' @@ -97,6 +97,8 @@ def get_observation_message(obs) -> dict[str, str] | None: elif isinstance(obs, AgentDelegateObservation): content = 'OBSERVATION:\n' + truncate_content(str(obs.outputs)) return {'role': 'user', 'content': content} + elif isinstance(obs, AgentSummarizeAction): + return {'role': 'user', 'content': obs.summarized_observations} return None @@ -262,14 +264,29 @@ class CodeActAgent(Agent): ] for event in state.history.get_events(): + # split summarize message into action and observation + if isinstance(event, AgentSummarizeAction): + action_message = get_action_message(event) + if action_message: + messages.append(action_message) + observation_message = get_observation_message(event) + if observation_message: + messages.append(observation_message) + continue + + # find regular message message = ( get_action_message(event) if isinstance(event, Action) else get_observation_message(event) ) + + # add regular message if message: messages.append(message) + # the latest user message is important: + # we want to remind the agent of the environment constraints latest_user_message = next( (m for m in reversed(messages) if m['role'] == 'user'), None ) @@ -277,11 +294,11 @@ class CodeActAgent(Agent): if latest_user_message: if state.almost_stuck == 1: latest_user_message['content'] += ( - '\n\nENVIRONMENT REMINDER: You are almost stuck repeating the same action. You have only 1 iteration left and you must change your approach. Now.' + '\n\nENVIRONMENT REMINDER: You are almost stuck, repeating the same action. You have only 1 chance left before you fail. You MUST change your approach. Re-think the problem. Do NOT repeat the same action again, you will fail.' ) elif state.almost_stuck == 2: latest_user_message['content'] += ( - '\n\nENVIRONMENT REMINDER: You are almost stuck repeating the same action. You have only 2 iterations left and you must change your approach.' + '\n\nENVIRONMENT REMINDER: You are almost stuck, repeating the same action. You have only 2 iterations left before you fail. Do NOT repeat the same action again, you will fail the same as before. Re-think the problem.' ) else: latest_user_message['content'] += ( diff --git a/opendevin/core/main.py b/opendevin/core/main.py index 3ca9cb6bc9..66da67b712 100644 --- a/opendevin/core/main.py +++ b/opendevin/core/main.py @@ -85,7 +85,7 @@ async def main( AgentCls: Type[Agent] = Agent.get_cls(args.agent_cls) agent = AgentCls(llm=llm) - event_stream = EventStream('main' + (f'_{sid if sid else ""}')) + event_stream = EventStream('main' + ('_' + sid if sid else '')) # restore main session if enabled initial_state = None diff --git a/opendevin/events/action/agent.py b/opendevin/events/action/agent.py index 3b8c588dd6..280dd9b22d 100644 --- a/opendevin/events/action/agent.py +++ b/opendevin/events/action/agent.py @@ -37,12 +37,12 @@ class AgentSummarizeAction(Action): Action to summarize a list of events. Attributes: - - actions: A comma-separated list of all the action names from the summarized actions. - - summary: A single sentence summarizing all the observations. + - summarized_actions: A sentence summarizing all the actions. + - summarized_observations: A few sentences summarizing all the observations. """ summarized_actions: str = '' - summary: str = '' + summarized_observations: str = '' action: str = ActionType.SUMMARIZE _chunk_start: int = -1 _chunk_end: int = -1 @@ -50,11 +50,12 @@ class AgentSummarizeAction(Action): @property def message(self) -> str: - return self.summary + return self.summarized_observations def __str__(self) -> str: ret = '**AgentSummarizeAction**\n' - ret += f'SUMMARY: {self.summary}' + ret += f'SUMMARIZED ACTIONS: {self.summarized_actions}\n' + ret += f'SUMMARIZED OBSERVATIONS: {self.summarized_observations}\n' return ret diff --git a/opendevin/memory/prompts.py b/opendevin/memory/prompts.py index 2ebe5f339d..31fa9f9730 100644 --- a/opendevin/memory/prompts.py +++ b/opendevin/memory/prompts.py @@ -6,14 +6,25 @@ from opendevin.core.exceptions import ( from opendevin.core.logger import opendevin_logger as logger from opendevin.core.utils import json from opendevin.events.action.agent import AgentSummarizeAction +from opendevin.events.event import EventSource from opendevin.events.serialization.action import action_from_dict SUMMARY_PROMPT = """ Given the following actions and observations, create a JSON response with: - "action": "summarize" - args: - - "summarized_actions": A comma-separated list of unique action names from the provided actions - - "summary": A single sentence summarizing all the provided observations + - "summarized_actions": A sentence summarizing all the provided actions, at first person + - "summarized observations": A few sentences summarizing all the provided observations, at third person + +Example: + { + "action": "summarize", + "args": { + "summarized_actions": "I opened the uml file.", + "summarized observations": "The agent ran a python script to open the uml.pdf file." + } + } +Make sure to include in observations any relevant information that the agent should remember. %(events)s """ @@ -46,6 +57,7 @@ def parse_summary_response(response: str) -> AgentSummarizeAction: error_message = f'Expected a summarize action, but the response got {str(type(action)) if action else None}' logger.error(error_message) raise InvalidSummaryResponseError(error_message) + action._source = EventSource.AGENT # type: ignore except (LLMResponseError, LLMMalformedActionError) as e: logger.error(f'Failed to parse summary response: {e}') raise InvalidSummaryResponseError(