Skip to content

Commit

Permalink
Merge branch 'master' into fix_remove_colors_dict_bug
Browse files Browse the repository at this point in the history
  • Loading branch information
collijk authored Apr 30, 2023
2 parents a3b5be4 + 6997bb0 commit 0fd225b
Show file tree
Hide file tree
Showing 12 changed files with 2,556 additions and 39 deletions.
19 changes: 19 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,22 @@ When you run Pytest locally:
- Or: The test might be poorly written. In that case, you can make suggestions to change the test.

In our CI pipeline, Pytest will use the cassettes and not call paid API providers, so we need your help to record the replays that you break.


### Community Challenges
Challenges are goals we need Auto-GPT to achieve.
To pick the challenge you like, go to the tests/integration/challenges folder and select the areas you would like to work on.
- a challenge is new if level_currently_beaten is None
- a challenge is in progress if level_currently_beaten is greater or equal to 1
- a challenge is beaten if level_currently_beaten = max_level

Here is an example of how to run the memory challenge A and attempt to beat level 3.

pytest -s tests/integration/challenges/memory/test_memory_challenge_a.py --level=3

To beat a challenge, you're not allowed to change anything in the tests folder, you have to add code in the autogpt folder

Challenges use cassettes. Cassettes allow us to replay your runs in our CI pipeline.
Don't hesitate to delete the cassettes associated to the challenge you're working on if you need to. Otherwise it will keep replaying the last run.

Once you've beaten a new level of a challenge, please create a pull request and we will analyze how you changed Auto-GPT to beat the challenge.
47 changes: 46 additions & 1 deletion tests/integration/agent_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from autogpt.agent import Agent
from autogpt.commands.command import CommandRegistry
from autogpt.config import AIConfig, Config
from autogpt.memory import NoMemory, get_memory
from autogpt.memory import LocalCache, NoMemory, get_memory
from autogpt.prompts.prompt import DEFAULT_TRIGGERING_PROMPT
from autogpt.workspace import Workspace

Expand All @@ -19,6 +19,16 @@ def agent_test_config(config: Config):
config.set_temperature(was_temperature)


@pytest.fixture
def memory_local_cache(agent_test_config: Config):
was_memory_backend = agent_test_config.memory_backend

agent_test_config.set_memory_backend("local_cache")
yield get_memory(agent_test_config, init=True)

agent_test_config.set_memory_backend(was_memory_backend)


@pytest.fixture
def memory_none(agent_test_config: Config):
was_memory_backend = agent_test_config.memory_backend
Expand Down Expand Up @@ -101,3 +111,38 @@ def writer_agent(agent_test_config, memory_none: NoMemory, workspace: Workspace)
)

return agent


@pytest.fixture
def memory_management_agent(
agent_test_config, memory_local_cache, workspace: Workspace
):
command_registry = CommandRegistry()
command_registry.import_commands("autogpt.commands.file_operations")
command_registry.import_commands("autogpt.app")

ai_config = AIConfig(
ai_name="Follow-Instructions-GPT",
ai_role="an AI designed to read the instructions_1.txt file using the read_file method and follow the instructions in the file.",
ai_goals=[
"Use the command read_file to read the instructions_1.txt file",
"Follow the instructions in the instructions_1.txt file",
],
)
ai_config.command_registry = command_registry

system_prompt = ai_config.construct_full_prompt()

agent = Agent(
ai_name="",
memory=memory_local_cache,
full_message_history=[],
command_registry=command_registry,
config=ai_config,
next_action_count=0,
system_prompt=system_prompt,
triggering_prompt=DEFAULT_TRIGGERING_PROMPT,
workspace_directory=workspace.root,
)

return agent
Empty file.
17 changes: 17 additions & 0 deletions tests/integration/challenges/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest


def pytest_addoption(parser):
parser.addoption(
"--level", action="store", default=None, type=int, help="Specify test level"
)


def pytest_configure(config):
config.option.level = config.getoption("--level")


@pytest.fixture
def user_selected_level(request) -> int:
## used for challenges in the goal oriented tests
return request.config.option.level
Empty file.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions tests/integration/challenges/memory/test_memory_challenge_a.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import pytest

from autogpt.agent import Agent
from autogpt.commands.file_operations import read_file, write_to_file
from tests.integration.agent_utils import run_interaction_loop
from tests.integration.challenges.utils import get_level_to_run
from tests.utils import requires_api_key

LEVEL_CURRENTLY_BEATEN = 3
MAX_LEVEL = 5


@pytest.mark.vcr
@requires_api_key("OPENAI_API_KEY")
def test_memory_challenge_a(
memory_management_agent: Agent, user_selected_level: int
) -> None:
"""
The agent reads a file containing a task_id. Then, it reads a series of other files.
After reading 'n' files, the agent must write the task_id into a new file.
Args:
memory_management_agent (Agent)
user_selected_level (int)
"""

num_files = get_level_to_run(user_selected_level, LEVEL_CURRENTLY_BEATEN, MAX_LEVEL)

task_id = "2314"
create_instructions_files(memory_management_agent, num_files, task_id)

try:
run_interaction_loop(memory_management_agent, 40)
# catch system exit exceptions
except SystemExit:
file_path = str(memory_management_agent.workspace.get_path("output.txt"))
content = read_file(file_path)
assert task_id in content, f"Expected the file to contain {task_id}"


def create_instructions_files(
memory_management_agent: Agent,
num_files: int,
task_id: str,
base_filename: str = "instructions_",
) -> None:
"""
Creates a series of instructions files for the memory challenge.
Args:
memory_management_agent (Agent)
num_files (int)
task_id (str)
base_filename (str, optional)
"""
for i in range(1, num_files + 1):
content = generate_content(i, task_id, base_filename, num_files)
file_name = f"{base_filename}{i}.txt"
file_path = str(memory_management_agent.workspace.get_path(file_name))
write_to_file(file_path, content)


def generate_content(
index: int, task_id: str, base_filename: str, num_files: int
) -> str:
"""
Args:
index: int
task_id: str
base_filename: str
num_files: int
Returns: str
"""
if index == 1:
return (
f"This task_id is {task_id}\nRead the file {base_filename}{index + 1}.txt"
)
if index != num_files:
return f"Read the file {base_filename}{index + 1}.txt"
return "Write the task_id into the file output.txt\nShutdown"
81 changes: 81 additions & 0 deletions tests/integration/challenges/memory/test_memory_challenge_b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import pytest

from autogpt.agent import Agent
from autogpt.commands.file_operations import read_file, write_to_file
from tests.integration.agent_utils import run_interaction_loop
from tests.integration.challenges.utils import generate_noise, get_level_to_run
from tests.utils import requires_api_key

LEVEL_CURRENTLY_BEATEN = 1
MAX_LEVEL = 5
NOISE = 1000


@pytest.mark.vcr
@requires_api_key("OPENAI_API_KEY")
def test_memory_challenge_b(
memory_management_agent: Agent, user_selected_level: int
) -> None:
"""
The agent reads a series of files, each containing a task_id and noise. After reading 'n' files,
the agent must write all the task_ids into a new file, filtering out the noise.
Args:
memory_management_agent (Agent)
user_selected_level (int)
"""

current_level = get_level_to_run(
user_selected_level, LEVEL_CURRENTLY_BEATEN, MAX_LEVEL
)
task_ids = [str(i * 1111) for i in range(1, current_level + 1)]
create_instructions_files(memory_management_agent, current_level, task_ids)

try:
run_interaction_loop(memory_management_agent, 40)
except SystemExit:
file_path = str(memory_management_agent.workspace.get_path("output.txt"))
content = read_file(file_path)
for task_id in task_ids:
assert task_id in content, f"Expected the file to contain {task_id}"


def create_instructions_files(
memory_management_agent: Agent,
level: int,
task_ids: list,
base_filename: str = "instructions_",
) -> None:
"""
Creates a series of instructions files for the memory challenge.
Args:
level:
memory_management_agent (Agent)
num_files (int)
task_ids (list)
base_filename (str, optional)
"""
for i in range(1, level + 1):
content = generate_content(i, task_ids, base_filename, level)
file_name = f"{base_filename}{i}.txt"
file_path = str(memory_management_agent.workspace.get_path(file_name))
write_to_file(file_path, content)


def generate_content(index: int, task_ids: list, base_filename: str, level: int) -> str:
"""
Args:
index: int
task_ids: list
base_filename: str
num_files: int
Returns: str
"""
task_id = task_ids[index - 1]
noise = generate_noise(NOISE)
if index != level:
if level == 1:
return f"{noise}\nThe current task_id is {task_id}.\n{noise}\nWrite all the task_ids into the file output.txt. The file has not been created yet. After that, use the task_complete command."
return f"{noise}\nThe current task_id is {task_id}.\n{noise}\nRead the file {base_filename}{index + 1}.txt using the read_file command."
return f"{noise}\nThis task_id is {task_id}\n{noise}\nWrite all the task_ids into the file output.txt. The file has not been created yet. After that, use the task_complete command.\n"
44 changes: 44 additions & 0 deletions tests/integration/challenges/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import random
from typing import Optional

import pytest


def get_level_to_run(
user_selected_level: Optional[int],
level_currently_beaten: Optional[int],
max_level: int,
) -> int:
"""
Determines the appropriate level to run for a challenge, based on user-selected level, level currently beaten, and maximum level.
Args:
user_selected_level (int | None): The level selected by the user. If not provided, the level currently beaten is used.
level_currently_beaten (int | None): The highest level beaten so far. If not provided, the test will be skipped.
max_level (int): The maximum level allowed for the challenge.
Returns:
int: The level to run for the challenge.
Raises:
ValueError: If the user-selected level is greater than the maximum level allowed.
"""
if user_selected_level is None:
if level_currently_beaten is None:
pytest.skip(
"No one has beaten any levels so we cannot run the test in our pipeline"
)
# by default we run the level currently beaten.
return level_currently_beaten
if user_selected_level > max_level:
raise ValueError(f"This challenge was not designed to go beyond {max_level}")
return user_selected_level


def generate_noise(noise_size) -> str:
return "".join(
random.choices(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
k=noise_size,
)
)
Empty file.
Loading

0 comments on commit 0fd225b

Please sign in to comment.