aboutsummaryrefslogtreecommitdiff
path: root/autogpts/autogpt/autogpt/app/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'autogpts/autogpt/autogpt/app/main.py')
-rw-r--r--autogpts/autogpt/autogpt/app/main.py159
1 files changed, 78 insertions, 81 deletions
diff --git a/autogpts/autogpt/autogpt/app/main.py b/autogpts/autogpt/autogpt/app/main.py
index f256c8707..aaab5fe48 100644
--- a/autogpts/autogpt/autogpt/app/main.py
+++ b/autogpts/autogpt/autogpt/app/main.py
@@ -18,11 +18,12 @@ from forge.sdk.db import AgentDB
if TYPE_CHECKING:
from autogpt.agents.agent import Agent
+ from autogpt.agents.base import BaseAgentActionProposal
from autogpt.agent_factory.configurators import configure_agent_with_state, create_agent
from autogpt.agent_factory.profile_generator import generate_agent_profile_for_task
from autogpt.agent_manager import AgentManager
-from autogpt.agents import AgentThoughts, CommandArgs, CommandName
+from autogpt.agents.prompt_strategies.one_shot import AssistantThoughts
from autogpt.commands.execute_code import (
is_docker_available,
we_are_running_in_a_docker_container,
@@ -40,6 +41,7 @@ from autogpt.file_storage import FileStorageBackendName, get_storage
from autogpt.logs.config import configure_logging
from autogpt.logs.helpers import print_attribute, speak
from autogpt.models.action_history import ActionInterruptedByHuman
+from autogpt.models.utils import ModelWithSummary
from autogpt.utils.exceptions import AgentTerminated, InvalidAgentResponseError
from autogpt.utils.utils import DEFAULT_FINISH_COMMAND
@@ -227,13 +229,12 @@ async def run_auto_gpt(
)
if (
- agent.event_history.current_episode
- and agent.event_history.current_episode.action.name
- == DEFAULT_FINISH_COMMAND
- and not agent.event_history.current_episode.result
+ (current_episode := agent.event_history.current_episode)
+ and current_episode.action.use_tool.name == DEFAULT_FINISH_COMMAND
+ and not current_episode.result
):
# Agent was resumed after `finish` -> rewrite result of `finish` action
- finish_reason = agent.event_history.current_episode.action.args["reason"]
+ finish_reason = current_episode.action.use_tool.arguments["reason"]
print(f"Agent previously self-terminated; reason: '{finish_reason}'")
new_assignment = clean_input(
config, "Please give a follow-up question or assignment:"
@@ -531,11 +532,7 @@ async def run_interaction_loop(
# Have the agent determine the next action to take.
with spinner:
try:
- (
- command_name,
- command_args,
- assistant_reply_dict,
- ) = (await agent.propose_action()).to_tuple()
+ action_proposal = await agent.propose_action()
except InvalidAgentResponseError as e:
logger.warning(f"The agent's thoughts could not be parsed: {e}")
consecutive_failures += 1
@@ -558,9 +555,7 @@ async def run_interaction_loop(
# Print the assistant's thoughts and the next command to the user.
update_user(
ai_profile,
- command_name,
- command_args,
- assistant_reply_dict,
+ action_proposal,
speak_mode=legacy_config.tts_config.speak_mode,
)
@@ -569,12 +564,12 @@ async def run_interaction_loop(
##################
handle_stop_signal()
if cycles_remaining == 1: # Last cycle
- user_feedback, user_input, new_cycles_remaining = await get_user_feedback(
+ feedback_type, feedback, new_cycles_remaining = await get_user_feedback(
legacy_config,
ai_profile,
)
- if user_feedback == UserFeedback.AUTHORIZE:
+ if feedback_type == UserFeedback.AUTHORIZE:
if new_cycles_remaining is not None:
# Case 1: User is altering the cycle budget.
if cycle_budget > 1:
@@ -598,13 +593,13 @@ async def run_interaction_loop(
"-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=",
extra={"color": Fore.MAGENTA},
)
- elif user_feedback == UserFeedback.EXIT:
+ elif feedback_type == UserFeedback.EXIT:
logger.warning("Exiting...")
exit()
else: # user_feedback == UserFeedback.TEXT
- command_name = "human_feedback"
+ pass
else:
- user_input = ""
+ feedback = ""
# First log new-line so user can differentiate sections better in console
print()
if cycles_remaining != math.inf:
@@ -619,33 +614,31 @@ async def run_interaction_loop(
# Decrement the cycle counter first to reduce the likelihood of a SIGINT
# happening during command execution, setting the cycles remaining to 1,
# and then having the decrement set it to 0, exiting the application.
- if command_name != "human_feedback":
+ if not feedback:
cycles_remaining -= 1
- if not command_name:
+ if not action_proposal.use_tool:
continue
handle_stop_signal()
- if command_name:
- result = await agent.execute(command_name, command_args, user_input)
+ if not feedback:
+ result = await agent.execute(action_proposal)
+ else:
+ result = await agent.do_not_execute(action_proposal, feedback)
- if result.status == "success":
- logger.info(
- result, extra={"title": "SYSTEM:", "title_color": Fore.YELLOW}
- )
- elif result.status == "error":
- logger.warning(
- f"Command {command_name} returned an error: "
- f"{result.error or result.reason}"
- )
+ if result.status == "success":
+ logger.info(result, extra={"title": "SYSTEM:", "title_color": Fore.YELLOW})
+ elif result.status == "error":
+ logger.warning(
+ f"Command {action_proposal.use_tool.name} returned an error: "
+ f"{result.error or result.reason}"
+ )
def update_user(
ai_profile: AIProfile,
- command_name: CommandName,
- command_args: CommandArgs,
- assistant_reply_dict: AgentThoughts,
+ action_proposal: "BaseAgentActionProposal",
speak_mode: bool = False,
) -> None:
"""Prints the assistant's thoughts and the next command to the user.
@@ -661,18 +654,19 @@ def update_user(
print_assistant_thoughts(
ai_name=ai_profile.ai_name,
- assistant_reply_json_valid=assistant_reply_dict,
+ thoughts=action_proposal.thoughts,
speak_mode=speak_mode,
)
if speak_mode:
- speak(f"I want to execute {command_name}")
+ speak(f"I want to execute {action_proposal.use_tool.name}")
# First log new-line so user can differentiate sections better in console
print()
+ safe_tool_name = remove_ansi_escape(action_proposal.use_tool.name)
logger.info(
- f"COMMAND = {Fore.CYAN}{remove_ansi_escape(command_name)}{Style.RESET_ALL} "
- f"ARGUMENTS = {Fore.CYAN}{command_args}{Style.RESET_ALL}",
+ f"COMMAND = {Fore.CYAN}{safe_tool_name}{Style.RESET_ALL} "
+ f"ARGUMENTS = {Fore.CYAN}{action_proposal.use_tool.arguments}{Style.RESET_ALL}",
extra={
"title": "NEXT ACTION:",
"title_color": Fore.CYAN,
@@ -741,56 +735,59 @@ async def get_user_feedback(
def print_assistant_thoughts(
ai_name: str,
- assistant_reply_json_valid: dict,
+ thoughts: str | ModelWithSummary | AssistantThoughts,
speak_mode: bool = False,
) -> None:
logger = logging.getLogger(__name__)
- assistant_thoughts_reasoning = None
- assistant_thoughts_plan = None
- assistant_thoughts_speak = None
- assistant_thoughts_criticism = None
-
- assistant_thoughts = assistant_reply_json_valid.get("thoughts", {})
- assistant_thoughts_text = remove_ansi_escape(assistant_thoughts.get("text", ""))
- if assistant_thoughts:
- assistant_thoughts_reasoning = remove_ansi_escape(
- assistant_thoughts.get("reasoning", "")
- )
- assistant_thoughts_plan = remove_ansi_escape(assistant_thoughts.get("plan", ""))
- assistant_thoughts_criticism = remove_ansi_escape(
- assistant_thoughts.get("self_criticism", "")
- )
- assistant_thoughts_speak = remove_ansi_escape(
- assistant_thoughts.get("speak", "")
- )
- print_attribute(
- f"{ai_name.upper()} THOUGHTS", assistant_thoughts_text, title_color=Fore.YELLOW
+ thoughts_text = remove_ansi_escape(
+ thoughts.text
+ if isinstance(thoughts, AssistantThoughts)
+ else thoughts.summary()
+ if isinstance(thoughts, ModelWithSummary)
+ else thoughts
)
- print_attribute("REASONING", assistant_thoughts_reasoning, title_color=Fore.YELLOW)
- if assistant_thoughts_plan:
- print_attribute("PLAN", "", title_color=Fore.YELLOW)
- # If it's a list, join it into a string
- if isinstance(assistant_thoughts_plan, list):
- assistant_thoughts_plan = "\n".join(assistant_thoughts_plan)
- elif isinstance(assistant_thoughts_plan, dict):
- assistant_thoughts_plan = str(assistant_thoughts_plan)
-
- # Split the input_string using the newline character and dashes
- lines = assistant_thoughts_plan.split("\n")
- for line in lines:
- line = line.lstrip("- ")
- logger.info(line.strip(), extra={"title": "- ", "title_color": Fore.GREEN})
print_attribute(
- "CRITICISM", f"{assistant_thoughts_criticism}", title_color=Fore.YELLOW
+ f"{ai_name.upper()} THOUGHTS", thoughts_text, title_color=Fore.YELLOW
)
- # Speak the assistant's thoughts
- if assistant_thoughts_speak:
- if speak_mode:
- speak(assistant_thoughts_speak)
- else:
- print_attribute("SPEAK", assistant_thoughts_speak, title_color=Fore.YELLOW)
+ if isinstance(thoughts, AssistantThoughts):
+ print_attribute(
+ "REASONING", remove_ansi_escape(thoughts.reasoning), title_color=Fore.YELLOW
+ )
+ if assistant_thoughts_plan := remove_ansi_escape(
+ "\n".join(f"- {p}" for p in thoughts.plan)
+ ):
+ print_attribute("PLAN", "", title_color=Fore.YELLOW)
+ # If it's a list, join it into a string
+ if isinstance(assistant_thoughts_plan, list):
+ assistant_thoughts_plan = "\n".join(assistant_thoughts_plan)
+ elif isinstance(assistant_thoughts_plan, dict):
+ assistant_thoughts_plan = str(assistant_thoughts_plan)
+
+ # Split the input_string using the newline character and dashes
+ lines = assistant_thoughts_plan.split("\n")
+ for line in lines:
+ line = line.lstrip("- ")
+ logger.info(
+ line.strip(), extra={"title": "- ", "title_color": Fore.GREEN}
+ )
+ print_attribute(
+ "CRITICISM",
+ remove_ansi_escape(thoughts.self_criticism),
+ title_color=Fore.YELLOW,
+ )
+
+ # Speak the assistant's thoughts
+ if assistant_thoughts_speak := remove_ansi_escape(thoughts.speak):
+ if speak_mode:
+ speak(assistant_thoughts_speak)
+ else:
+ print_attribute(
+ "SPEAK", assistant_thoughts_speak, title_color=Fore.YELLOW
+ )
+ else:
+ speak(thoughts_text)
def remove_ansi_escape(s: str) -> str: