Skip to content

Commit

Permalink
Pass agent to commands instead of config (#4645)
Browse files Browse the repository at this point in the history
* Add config as attribute to Agent, rename old config to ai_config

* Code review: Pass ai_config

* Pass agent to commands instead of config

* Lint

* Fix merge error

* Fix memory challenge a

---------

Co-authored-by: Nicholas Tindle <nick@ntindle.com>
Co-authored-by: merwanehamadi <merwanehamadi@gmail.com>
  • Loading branch information
3 people authored Jun 10, 2023
1 parent 097ce08 commit 0594ba3
Show file tree
Hide file tree
Showing 35 changed files with 390 additions and 386 deletions.
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

0 comments on commit 0594ba3

Please sign in to comment.