Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass agent to commands instead of config #4645

Merged
7 changes: 4 additions & 3 deletions autogpt/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from colorama import Fore, Style

from autogpt.app import execute_command, get_command
from autogpt.commands.command import CommandRegistry
from autogpt.config import Config
from autogpt.config.ai_config import AIConfig
Expand Down Expand Up @@ -89,6 +88,9 @@ def __init__(
).max_tokens

def start_interaction_loop(self):
# Avoid circular imports
from autogpt.app import execute_command, get_command

# Interaction Loop
self.cycle_count = 0
command_name = None
Expand Down Expand Up @@ -287,8 +289,7 @@ def signal_handler(signum, frame):
self.command_registry,
command_name,
arguments,
self.ai_config.prompt_generator,
config=self.config,
agent=self,
)
result = f"Command {command_name} returned: " f"{command_result}"

Expand Down
34 changes: 16 additions & 18 deletions autogpt/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
import json
from typing import Dict, List, Union

from autogpt.agent.agent import Agent
from autogpt.agent.agent_manager import AgentManager
from autogpt.commands.command import CommandRegistry, command
from autogpt.commands.web_requests import scrape_links, scrape_text
from autogpt.config import Config
from autogpt.processing.text import summarize_text
from autogpt.prompts.generator import PromptGenerator
from autogpt.speech import say_text
from autogpt.url_utils.validators import validate_url

Expand Down Expand Up @@ -87,9 +86,8 @@ def map_command_synonyms(command_name: str):
def execute_command(
command_registry: CommandRegistry,
command_name: str,
arguments,
prompt: PromptGenerator,
config: Config,
arguments: dict[str, str],
agent: Agent,
):
"""Execute the command and return the result

Expand All @@ -105,15 +103,15 @@ def execute_command(

# If the command is found, call it with the provided arguments
if cmd:
return cmd(**arguments, config=config)
return cmd(**arguments, agent=agent)

# TODO: Remove commands below after they are moved to the command registry.
command_name = map_command_synonyms(command_name.lower())

# TODO: Change these to take in a file rather than pasted code, if
# non-file is given, return instructions "Input should be a python
# filepath, write your code to file and try again
for command in prompt.commands:
for command in agent.prompt.commands:
if (
command_name == command["label"].lower()
or command_name == command["name"].lower()
Expand All @@ -132,7 +130,7 @@ def execute_command(
"get_text_summary", "Get text summary", '"url": "<url>", "question": "<question>"'
)
@validate_url
def get_text_summary(url: str, question: str, config: Config) -> str:
def get_text_summary(url: str, question: str, agent: Agent) -> str:
"""Get the text summary of a webpage

Args:
Expand All @@ -142,15 +140,15 @@ def get_text_summary(url: str, question: str, config: Config) -> str:
Returns:
str: The summary of the text
"""
text = scrape_text(url, config)
text = scrape_text(url, agent)
summary, _ = summarize_text(text, question=question)

return f""" "Result" : {summary}"""


@command("get_hyperlinks", "Get hyperlinks", '"url": "<url>"')
@validate_url
def get_hyperlinks(url: str, config: Config) -> Union[str, List[str]]:
def get_hyperlinks(url: str, agent: Agent) -> Union[str, List[str]]:
"""Get all hyperlinks on a webpage

Args:
Expand All @@ -159,15 +157,15 @@ def get_hyperlinks(url: str, config: Config) -> Union[str, List[str]]:
Returns:
str or list: The hyperlinks on the page
"""
return scrape_links(url, config)
return scrape_links(url, agent)


@command(
"start_agent",
"Start GPT Agent",
'"name": "<name>", "task": "<short_task_desc>", "prompt": "<prompt>"',
)
def start_agent(name: str, task: str, prompt: str, config: Config, model=None) -> str:
def start_agent(name: str, task: str, prompt: str, agent: Agent, model=None) -> str:
"""Start an agent with a given name, task, and prompt

Args:
Expand All @@ -188,11 +186,11 @@ def start_agent(name: str, task: str, prompt: str, config: Config, model=None) -
agent_intro = f"{voice_name} here, Reporting for duty!"

# Create agent
if config.speak_mode:
if agent.config.speak_mode:
say_text(agent_intro, 1)
key, ack = agent_manager.create_agent(task, first_message, model)

if config.speak_mode:
if agent.config.speak_mode:
say_text(f"Hello {voice_name}. Your task is as follows. {task}.")

# Assign task (prompt), get response
Expand All @@ -202,7 +200,7 @@ def start_agent(name: str, task: str, prompt: str, config: Config, model=None) -


@command("message_agent", "Message GPT Agent", '"key": "<key>", "message": "<message>"')
def message_agent(key: str, message: str, config: Config) -> str:
def message_agent(key: str, message: str, agent: Agent) -> str:
"""Message an agent with a given key and message"""
# Check if the key is a valid integer
if is_valid_int(key):
Expand All @@ -211,13 +209,13 @@ def message_agent(key: str, message: str, config: Config) -> str:
return "Invalid key, must be an integer."

# Speak response
if config.speak_mode:
if agent.config.speak_mode:
say_text(agent_response, 1)
return agent_response


@command("list_agents", "List GPT Agents", "() -> str")
def list_agents(config: Config) -> str:
def list_agents(agent: Agent) -> str:
"""List all agents

Returns:
Expand All @@ -229,7 +227,7 @@ def list_agents(config: Config) -> str:


@command("delete_agent", "Delete GPT Agent", '"key": "<key>"')
def delete_agent(key: str, config: Config) -> str:
def delete_agent(key: str, agent: Agent) -> str:
"""Delete an agent with a given key

Args:
Expand Down
12 changes: 5 additions & 7 deletions autogpt/commands/analyze_code.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
"""Code evaluation module."""
from __future__ import annotations

from typing import TYPE_CHECKING

from autogpt.agent.agent import Agent
from autogpt.commands.command import command
from autogpt.llm.utils import call_ai_function

if TYPE_CHECKING:
from autogpt.config import Config


@command(
"analyze_code",
"Analyze Code",
'"code": "<full_code_string>"',
)
def analyze_code(code: str, config: Config) -> list[str]:
def analyze_code(code: str, agent: Agent) -> list[str]:
"""
A function that takes in a string and returns a response from create chat
completion api call.
Expand All @@ -33,4 +29,6 @@ def analyze_code(code: str, config: Config) -> list[str]:
"Analyzes the given code and returns a list of suggestions for improvements."
)

return call_ai_function(function_string, args, description_string, config=config)
return call_ai_function(
function_string, args, description_string, config=agent.config
)
22 changes: 9 additions & 13 deletions autogpt/commands/audio_text.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
"""Commands for converting audio to text."""
import json
from typing import TYPE_CHECKING

import requests

from autogpt.agent.agent import Agent
from autogpt.commands.command import command
from autogpt.config import Config

if TYPE_CHECKING:
from autogpt.config import Config


@command(
Expand All @@ -19,7 +15,7 @@
and config.huggingface_api_token,
"Configure huggingface_audio_to_text_model and Hugging Face api token.",
)
def read_audio_from_file(filename: str, config: Config) -> str:
def read_audio_from_file(filename: str, agent: Agent) -> str:
"""
Convert audio to text.

Expand All @@ -31,10 +27,10 @@ def read_audio_from_file(filename: str, config: Config) -> str:
"""
with open(filename, "rb") as audio_file:
audio = audio_file.read()
return read_audio(audio, config)
return read_audio(audio, agent.config)


def read_audio(audio: bytes, config: Config) -> str:
def read_audio(audio: bytes, agent: Agent) -> str:
"""
Convert audio to text.

Expand All @@ -44,8 +40,8 @@ def read_audio(audio: bytes, config: Config) -> str:
Returns:
str: The text from the audio
"""
if config.audio_to_text_provider == "huggingface":
text = read_huggingface_audio(audio, config)
if agent.config.audio_to_text_provider == "huggingface":
text = read_huggingface_audio(audio, agent.config)
if text:
return f"The audio says: {text}"
else:
Expand All @@ -54,10 +50,10 @@ def read_audio(audio: bytes, config: Config) -> str:
return "Error: No audio to text provider given"


def read_huggingface_audio(audio: bytes, config: Config) -> str:
model = config.huggingface_audio_to_text_model
def read_huggingface_audio(audio: bytes, agent: Agent) -> str:
model = agent.config.huggingface_audio_to_text_model
api_url = f"https://api-inference.huggingface.co/models/{model}"
api_token = config.huggingface_api_token
api_token = agent.config.huggingface_api_token
headers = {"Authorization": f"Bearer {api_token}"}

if api_token is None:
Expand Down
36 changes: 19 additions & 17 deletions autogpt/commands/execute_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from pathlib import Path

import docker
from confection import Config
from docker.errors import ImageNotFound

from autogpt.agent.agent import Agent
from autogpt.commands.command import command
from autogpt.config import Config
from autogpt.config.ai_config import AIConfig
from autogpt.logs import logger
from autogpt.setup import CFG
from autogpt.workspace.workspace import Workspace
Expand All @@ -22,7 +22,7 @@
"Create a Python file and execute it",
'"code": "<code>", "basename": "<basename>"',
)
def execute_python_code(code: str, basename: str, config: Config) -> str:
def execute_python_code(code: str, basename: str, agent: Agent) -> str:
"""Create and execute a Python file in a Docker container and return the STDOUT of the
executed code. If there is any data that needs to be captured use a print statement

Expand All @@ -33,8 +33,8 @@ def execute_python_code(code: str, basename: str, config: Config) -> str:
Returns:
str: The STDOUT captured from the code when it ran
"""
ai_name = AIConfig.load(config.ai_settings_file).ai_name
directory = os.path.join(config.workspace_path, ai_name, "executed_code")
ai_name = agent.ai_name
directory = os.path.join(agent.config.workspace_path, ai_name, "executed_code")
os.makedirs(directory, exist_ok=True)

if not basename.endswith(".py"):
Expand All @@ -46,13 +46,13 @@ def execute_python_code(code: str, basename: str, config: Config) -> str:
with open(path, "w+", encoding="utf-8") as f:
f.write(code)

return execute_python_file(f.name, config)
return execute_python_file(f.name, agent)
except Exception as e:
return f"Error: {str(e)}"


@command("execute_python_file", "Execute Python File", '"filename": "<filename>"')
def execute_python_file(filename: str, config: Config) -> str:
def execute_python_file(filename: str, agent: Agent) -> str:
"""Execute a Python file in a Docker container and return the output

Args:
Expand All @@ -68,7 +68,9 @@ def execute_python_file(filename: str, config: Config) -> str:
if not filename.endswith(".py"):
return "Error: Invalid file type. Only .py files are allowed."

workspace = Workspace(config.workspace_path, config.restrict_to_workspace)
workspace = Workspace(
agent.config.workspace_path, agent.config.restrict_to_workspace
)

path = workspace.get_path(filename)
if not path.is_file():
Expand Down Expand Up @@ -116,7 +118,7 @@ def execute_python_file(filename: str, config: Config) -> str:
image_name,
["python", str(path.relative_to(workspace.root))],
volumes={
config.workspace_path: {
agent.config.workspace_path: {
"bind": "/workspace",
"mode": "ro",
}
Expand Down Expand Up @@ -175,7 +177,7 @@ def validate_command(command: str, config: Config) -> bool:
" shell commands, EXECUTE_LOCAL_COMMANDS must be set to 'True' "
"in your config file: .env - do not attempt to bypass the restriction.",
)
def execute_shell(command_line: str, config: Config) -> str:
def execute_shell(command_line: str, agent: Agent) -> str:
"""Execute a shell command and return the output

Args:
Expand All @@ -184,14 +186,14 @@ def execute_shell(command_line: str, config: Config) -> str:
Returns:
str: The output of the command
"""
if not validate_command(command_line, config):
if not validate_command(command_line, agent.config):
logger.info(f"Command '{command_line}' not allowed")
return "Error: This Shell Command is not allowed."

current_dir = Path.cwd()
# Change dir into workspace if necessary
if not current_dir.is_relative_to(config.workspace_path):
os.chdir(config.workspace_path)
if not current_dir.is_relative_to(agent.config.workspace_path):
os.chdir(agent.config.workspace_path)

logger.info(
f"Executing command '{command_line}' in working directory '{os.getcwd()}'"
Expand All @@ -215,7 +217,7 @@ def execute_shell(command_line: str, config: Config) -> str:
" shell commands, EXECUTE_LOCAL_COMMANDS must be set to 'True' "
"in your config. Do not attempt to bypass the restriction.",
)
def execute_shell_popen(command_line, config: Config) -> str:
def execute_shell_popen(command_line, agent: Agent) -> str:
"""Execute a shell command with Popen and returns an english description
of the event and the process id

Expand All @@ -225,14 +227,14 @@ def execute_shell_popen(command_line, config: Config) -> str:
Returns:
str: Description of the fact that the process started and its id
"""
if not validate_command(command_line, config):
if not validate_command(command_line, agent.config):
logger.info(f"Command '{command_line}' not allowed")
return "Error: This Shell Command is not allowed."

current_dir = os.getcwd()
# Change dir into workspace if necessary
if config.workspace_path not in current_dir:
os.chdir(config.workspace_path)
if agent.config.workspace_path not in current_dir:
os.chdir(agent.config.workspace_path)

logger.info(
f"Executing command '{command_line}' in working directory '{os.getcwd()}'"
Expand Down
Loading