diff --git a/autogpts/autogpt/autogpt/agents/base.py b/autogpts/autogpt/autogpt/agents/base.py index f71d8c7a8b..52a9a132bd 100644 --- a/autogpts/autogpt/autogpt/agents/base.py +++ b/autogpts/autogpt/autogpt/agents/base.py @@ -177,14 +177,6 @@ class BaseAgent(Configurable[BaseAgentSettings], ABC): self.legacy_config = legacy_config """LEGACY: Monolithic application configuration.""" - # In case the agent is resumed, cursor is set to the last episode - if self.event_history: - # To prevent errors, when the last action is "finish", we register a result - # And move cursor to the next action - if self.event_history.current_episode.action.name == "finish": - self.event_history.register_result(ActionSuccessResult()) - self.event_history.cursor = len(self.event_history) - self.llm_provider = llm_provider self.prompt_strategy = prompt_strategy diff --git a/autogpts/autogpt/autogpt/agents/utils/exceptions.py b/autogpts/autogpt/autogpt/agents/utils/exceptions.py index 704922b0aa..211c8443c0 100644 --- a/autogpts/autogpt/autogpt/agents/utils/exceptions.py +++ b/autogpts/autogpt/autogpt/agents/utils/exceptions.py @@ -18,6 +18,10 @@ class AgentTerminated(AgentException): """The agent terminated or was terminated""" +class AgentFinished(AgentTerminated): + """The agent self-terminated""" + + class ConfigurationError(AgentException): """Error caused by invalid, incompatible or otherwise incorrect configuration""" diff --git a/autogpts/autogpt/autogpt/app/agent_protocol_server.py b/autogpts/autogpt/autogpt/app/agent_protocol_server.py index 5118782d15..0df2bd13b9 100644 --- a/autogpts/autogpt/autogpt/app/agent_protocol_server.py +++ b/autogpts/autogpt/autogpt/app/agent_protocol_server.py @@ -30,6 +30,7 @@ from sentry_sdk import set_user from autogpt.agent_factory.configurators import configure_agent_with_state from autogpt.agent_factory.generators import generate_agent_for_task from autogpt.agent_manager import AgentManager +from autogpt.agents.utils.exceptions import AgentFinished from autogpt.commands.system import finish from autogpt.commands.user_interaction import ask_user from autogpt.config import Config @@ -230,26 +231,6 @@ class AgentProtocolServer: task=task, step=step, relative_path=path ) - if step.is_last and execute_command == finish.__name__: - assert execute_command_args - - additional_output = {} - task_total_cost = agent.llm_provider.get_incurred_cost() - if task_total_cost > 0: - additional_output["task_total_cost"] = task_total_cost - logger.info( - f"Total LLM cost for task {task_id}: " - f"${round(task_total_cost, 2)}" - ) - - step = await self.db.update_step( - task_id=task_id, - step_id=step.step_id, - output=execute_command_args["reason"], - additional_output=additional_output, - ) - return step - if execute_command == ask_user.__name__: # HACK execute_result = ActionSuccessResult(outputs=user_input) agent.event_history.register_result(execute_result) @@ -261,11 +242,31 @@ class AgentProtocolServer: step_id=step.step_id, status="running", ) - # Execute previously proposed action - execute_result = await agent.execute( - command_name=execute_command, - command_args=execute_command_args, - ) + + try: + # Execute previously proposed action + execute_result = await agent.execute( + command_name=execute_command, + command_args=execute_command_args, + ) + except AgentFinished: + additional_output = {} + task_total_cost = agent.llm_provider.get_incurred_cost() + if task_total_cost > 0: + additional_output["task_total_cost"] = task_total_cost + logger.info( + f"Total LLM cost for task {task_id}: " + f"${round(task_total_cost, 2)}" + ) + + step = await self.db.update_step( + task_id=task_id, + step_id=step.step_id, + output=execute_command_args["reason"], + additional_output=additional_output, + ) + await agent.save_state() + return step else: assert user_input execute_result = await agent.execute( diff --git a/autogpts/autogpt/autogpt/app/main.py b/autogpts/autogpt/autogpt/app/main.py index ad04bad8fb..e6978d7ac5 100644 --- a/autogpts/autogpt/autogpt/app/main.py +++ b/autogpts/autogpt/autogpt/app/main.py @@ -16,8 +16,6 @@ from typing import TYPE_CHECKING, Optional from colorama import Fore, Style from forge.sdk.db import AgentDB -from autogpt.file_storage import FileStorageBackendName, get_storage - if TYPE_CHECKING: from autogpt.agents.agent import Agent @@ -26,6 +24,7 @@ from autogpt.agent_factory.profile_generator import generate_agent_profile_for_t from autogpt.agent_manager import AgentManager from autogpt.agents import AgentThoughts, CommandArgs, CommandName from autogpt.agents.utils.exceptions import AgentTerminated, InvalidAgentResponseError +from autogpt.commands.system import finish from autogpt.config import ( AIDirectives, AIProfile, @@ -35,8 +34,10 @@ from autogpt.config import ( ) from autogpt.core.resource.model_providers.openai import OpenAIProvider from autogpt.core.runner.client_lib.utils import coroutine +from autogpt.file_storage import FileStorageBackendName, get_storage from autogpt.logs.config import configure_chat_plugins, configure_logging from autogpt.logs.helpers import print_attribute, speak +from autogpt.models.action_history import ActionInterruptedByHuman from autogpt.plugins import scan_plugins from scripts.install_plugin_deps import install_plugin_dependencies @@ -217,6 +218,21 @@ async def run_auto_gpt( replace_directives=override_directives, ) + if ( + agent.event_history.current_episode + and agent.event_history.current_episode.action.name == finish.__name__ + and not agent.event_history.current_episode.result + ): + # Agent was resumed after `finish` -> rewrite result of `finish` action + finish_reason = agent.event_history.current_episode.action.args["reason"] + print(f"Agent previously self-terminated; reason: '{finish_reason}'") + new_assignment = await clean_input( + config, "Please give a follow-up question or assignment:" + ) + agent.event_history.register_result( + ActionInterruptedByHuman(feedback=new_assignment) + ) + # If any of these are specified as arguments, # assume the user doesn't want to revise them if not any( diff --git a/autogpts/autogpt/autogpt/commands/system.py b/autogpts/autogpt/autogpt/commands/system.py index bd184122fa..2d547bd08b 100644 --- a/autogpts/autogpt/autogpt/commands/system.py +++ b/autogpts/autogpt/autogpt/commands/system.py @@ -6,7 +6,7 @@ import logging from typing import TYPE_CHECKING from autogpt.agents.features.context import get_agent_context -from autogpt.agents.utils.exceptions import AgentTerminated, InvalidArgumentError +from autogpt.agents.utils.exceptions import AgentFinished, InvalidArgumentError from autogpt.command_decorator import command from autogpt.core.utils.json_schema import JSONSchema @@ -44,7 +44,7 @@ def finish(reason: str, agent: Agent) -> None: A result string from create chat completion. A list of suggestions to improve the code. """ - raise AgentTerminated(reason) + raise AgentFinished(reason) @command(