Skip to content

Commit

Permalink
Merge pull request #887 from ATheorell/naming_suggestions
Browse files Browse the repository at this point in the history
Naming suggestions
  • Loading branch information
ATheorell authored Dec 6, 2023
2 parents 8357c08 + 17f0feb commit a3b7f88
Show file tree
Hide file tree
Showing 30 changed files with 298 additions and 281 deletions.
80 changes: 48 additions & 32 deletions gpt_engineer/applications/cli/cli_agent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from gpt_engineer.core.code import Code
from gpt_engineer.core.files_dict import FilesDict

# from gpt_engineer.core.default.git_version_manager import GitVersionManager
from gpt_engineer.core.ai import AI
Expand All @@ -8,22 +8,26 @@
execute_entrypoint,
improve,
)
from gpt_engineer.core.repository import Repository
from gpt_engineer.core.default.on_disk_repository import OnDiskRepository
from gpt_engineer.core.execution_env import ExecutionEnv
from gpt_engineer.core.default.on_disk_execution_env import OnDiskExecutionEnv
from gpt_engineer.core.base_memory import BaseMemory
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.base_execution_env import BaseExecutionEnv
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
from gpt_engineer.core.default.paths import memory_path, ENTRYPOINT_FILE, PREPROMPTS_PATH
from gpt_engineer.core.agent import Agent
from gpt_engineer.core.base_agent import BaseAgent
from gpt_engineer.core.preprompts_holder import PrepromptsHolder
from typing import TypeVar, Callable, Union
from pathlib import Path

CodeGenType = TypeVar("CodeGenType", bound=Callable[[AI, str, Repository], Code])
CodeProcessor = TypeVar("CodeProcessor", bound=Callable[[AI, ExecutionEnv, Code], Code])
ImproveType = TypeVar("ImproveType", bound=Callable[[AI, str, Code, Repository], Code])
CodeGenType = TypeVar("CodeGenType", bound=Callable[[AI, str, BaseMemory], FilesDict])
CodeProcessor = TypeVar(
"CodeProcessor", bound=Callable[[AI, BaseExecutionEnv, FilesDict], FilesDict]
)
ImproveType = TypeVar(
"ImproveType", bound=Callable[[AI, str, FilesDict, BaseMemory], FilesDict]
)


class CliAgent(Agent):
class CliAgent(BaseAgent):
"""
The `Agent` class is responsible for managing the lifecycle of code generation and improvement.
Expand Down Expand Up @@ -51,7 +55,7 @@ class CliAgent(Agent):
prompt (str): A string prompt that guides the code generation process.
Returns:
Code: An instance of the `Code` class containing the generated code.
FilesDict: An instance of the `Code` class containing the generated code.
improve(self, prompt: str) -> Code:
Improves an existing piece of code using the AI and step bundle based on the provided prompt.
Expand All @@ -61,13 +65,13 @@ class CliAgent(Agent):
prompt (str): A string prompt that guides the code improvement process.
Returns:
Code: An instance of the `Code` class containing the improved code.
FilesDict: An instance of the `Code` class containing the improved code.
"""

def __init__(
self,
memory: Repository,
execution_env: ExecutionEnv,
memory: BaseMemory,
execution_env: BaseExecutionEnv,
ai: AI = None,
code_gen_fn: CodeGenType = gen_code,
improve_fn: ImproveType = improve,
Expand All @@ -85,8 +89,8 @@ def __init__(
@classmethod
def with_default_config(
cls,
memory: OnDiskRepository,
execution_env: OnDiskExecutionEnv,
memory: DiskMemory,
execution_env: DiskExecutionEnv,
ai: AI = None,
code_gen_fn: CodeGenType = gen_code,
improve_fn: ImproveType = improve,
Expand All @@ -103,25 +107,37 @@ def with_default_config(
preprompts_holder=preprompts_holder or PrepromptsHolder(PREPROMPTS_PATH),
)

def init(self, prompt: str) -> Code:
code = self.code_gen_fn(self.ai, prompt, self.memory, self.preprompts_holder)
entrypoint = gen_entrypoint(self.ai, code, self.memory, self.preprompts_holder)
code = Code(code | entrypoint)
code = self.process_code_fn(
self.ai, self.execution_env, code, preprompts_holder=self.preprompts_holder
def init(self, prompt: str) -> FilesDict:
files_dict = self.code_gen_fn(
self.ai, prompt, self.memory, self.preprompts_holder
)
entrypoint = gen_entrypoint(
self.ai, files_dict, self.memory, self.preprompts_holder
)
return code
files_dict = FilesDict(files_dict | entrypoint)
files_dict = self.process_code_fn(
self.ai,
self.execution_env,
files_dict,
preprompts_holder=self.preprompts_holder,
)
return files_dict

def improve(
self, code: Code, prompt: str, execution_command: str | None = None
) -> Code:
code = self.improve_fn(self.ai, prompt, code, self.memory, self.preprompts_holder)
if not execution_command and ENTRYPOINT_FILE not in code:
self, files_dict: FilesDict, prompt: str, execution_command: str | None = None
) -> FilesDict:
files_dict = self.improve_fn(
self.ai, prompt, files_dict, self.memory, self.preprompts_holder
)
if not execution_command and ENTRYPOINT_FILE not in files_dict:
entrypoint = gen_entrypoint(
self.ai, code, self.memory, self.preprompts_holder
self.ai, files_dict, self.memory, self.preprompts_holder
)
code = Code(code | entrypoint)
code = self.process_code_fn(
self.ai, self.execution_env, code, preprompts_holder=self.preprompts_holder
files_dict = FilesDict(files_dict | entrypoint)
files_dict = self.process_code_fn(
self.ai,
self.execution_env,
files_dict,
preprompts_holder=self.preprompts_holder,
)
return code
return files_dict
6 changes: 3 additions & 3 deletions gpt_engineer/applications/cli/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from typing import List, Tuple

from gpt_engineer.core.default.on_disk_repository import OnDiskRepository
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.applications.cli.learning import (
Learning,
extract_learning,
Expand Down Expand Up @@ -68,7 +68,7 @@ def collect_learnings(
model: str,
temperature: float,
config: any,
memory: OnDiskRepository,
memory: DiskMemory,
review: Review,
):
"""
Expand Down Expand Up @@ -134,7 +134,7 @@ def collect_and_send_human_review(
model: str,
temperature: float,
config: Tuple[str, ...],
memory: OnDiskRepository,
memory: DiskMemory,
):
"""
Collects human feedback on the code and stores it in memory.
Expand Down
14 changes: 7 additions & 7 deletions gpt_engineer/applications/cli/file_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
from pathlib import Path
from typing import List, Union

from gpt_engineer.core.default.on_disk_repository import OnDiskRepository
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.default.paths import metadata_path
from gpt_engineer.core.code import Code
from gpt_engineer.core.files_dict import FilesDict

IGNORE_FOLDERS = {"site-packages", "node_modules", "venv"}
FILE_LIST_NAME = "file_list.txt"
Expand Down Expand Up @@ -326,15 +326,15 @@ def is_in_ignoring_extensions(path: Path) -> bool:
return is_hidden and is_pycache


def ask_for_files(project_path: Union[str, Path]) -> Code:
def ask_for_files(project_path: Union[str, Path]) -> FilesDict:
"""
Ask user to select files to improve.
It can be done by terminal, gui, or using the old selection.
Returns:
dict[str, str]: Dictionary where key = file name and value = file path
"""
metadata_db = OnDiskRepository(metadata_path(project_path))
metadata_db = DiskMemory(metadata_path(project_path))
if FILE_LIST_NAME in metadata_db:
print(
f"File list detected at {metadata_db.path / FILE_LIST_NAME}. "
Expand Down Expand Up @@ -399,10 +399,10 @@ def ask_for_files(project_path: Union[str, Path]) -> Code:
for file in file_list:
with open(os.path.join(project_path, file.strip()), "r") as content:
content_dict[file.strip()] = content.read()
return Code(content_dict)
return FilesDict(content_dict)


def get_all_code(project_path: str) -> Code:
def get_all_code(project_path: str) -> FilesDict:
file_selection = terminal_file_selector(project_path, all=True)
# ToDO: Replace this hack that makes all file_path relative to the right thing
file_selection = [
Expand All @@ -414,7 +414,7 @@ def get_all_code(project_path: str) -> Code:
for file in file_selection:
with open(os.path.join(project_path, file.strip()), "r") as content:
content_dict[file.strip()] = content.read()
return Code(content_dict)
return FilesDict(content_dict)


def gui_file_selector(input_path: str) -> List[str]:
Expand Down
4 changes: 2 additions & 2 deletions gpt_engineer/applications/cli/learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from dataclasses_json import dataclass_json
from termcolor import colored

from gpt_engineer.core.default.on_disk_repository import OnDiskRepository
from gpt_engineer.core.default.disk_memory import DiskMemory


@dataclass_json
Expand Down Expand Up @@ -188,7 +188,7 @@ def extract_learning(
model: str,
temperature: float,
config: Tuple[str, ...],
memory: OnDiskRepository,
memory: DiskMemory,
review: Review,
) -> Learning:
"""
Expand Down
28 changes: 14 additions & 14 deletions gpt_engineer/applications/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import typer
from dotenv import load_dotenv

from gpt_engineer.core.default.disk_store import FileStore
from gpt_engineer.core.default.on_disk_repository import OnDiskRepository
from gpt_engineer.core.default.file_store import FileStore
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.ai import AI
from gpt_engineer.core.default.paths import PREPROMPTS_PATH, memory_path
from gpt_engineer.applications.cli.file_selector import ask_for_files, get_all_code
Expand All @@ -49,7 +49,7 @@
from gpt_engineer.applications.cli.cli_agent import CliAgent
from gpt_engineer.applications.cli.collect import collect_and_send_human_review
from gpt_engineer.core.preprompts_holder import PrepromptsHolder
from gpt_engineer.core.default.on_disk_execution_env import OnDiskExecutionEnv
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv
import logging

app = typer.Typer() # creates a CLI app
Expand All @@ -64,7 +64,7 @@ def load_env_if_needed():
openai.api_key = os.getenv("OPENAI_API_KEY")


def load_prompt(input_repo: OnDiskRepository, improve_mode):
def load_prompt(input_repo: DiskMemory, improve_mode):
if input_repo.get("prompt"):
return input_repo.get("prompt")

Expand Down Expand Up @@ -101,12 +101,12 @@ def main(
False,
"--improve",
"-i",
help="Improve code from existing project.",
help="Improve files_dict from existing project.",
),
improve_all_mode: bool = typer.Option(
False,
"--improve_all_experimental",
help="Improve code from existing project, without manually choosing which files to improve, using vector store (EXPERIMENTAL).",
help="Improve files_dict from existing project, without manually choosing which files to improve, using vector store (EXPERIMENTAL).",
),
lite_mode: bool = typer.Option(
False,
Expand Down Expand Up @@ -171,7 +171,7 @@ def main(
# ) # resolve the string to a valid path (eg "a/b/../c" to "a/c")
path = Path(project_path) # .absolute()
print("Running gpt-engineer in", path.absolute(), "\n")
prompt = load_prompt(OnDiskRepository(path), improve_mode)
prompt = load_prompt(DiskMemory(path), improve_mode)
# configure generation function
if clarify_mode:
code_gen_fn = clarified_gen
Expand All @@ -192,8 +192,8 @@ def main(

preprompts_path = get_preprompts_path(use_custom_preprompts, Path(project_path))
preprompts_holder = PrepromptsHolder(preprompts_path)
memory = OnDiskRepository(memory_path(project_path))
execution_env = OnDiskExecutionEnv()
memory = DiskMemory(memory_path(project_path))
execution_env = DiskExecutionEnv()
agent = CliAgent.with_default_config(
memory,
execution_env,
Expand All @@ -207,14 +207,14 @@ def main(
store = FileStore(project_path)
if improve_mode:
if improve_all_mode:
code = store.download()
files_dict = store.download()
else:
code = ask_for_files(project_path)
code = agent.improve(code, prompt)
files_dict = ask_for_files(project_path)
files_dict = agent.improve(files_dict, prompt)
else:
code = agent.init(prompt)
files_dict = agent.init(prompt)

store.upload(code)
store.upload(files_dict)

# collect user feedback if user consents
config = (code_gen_fn.__name__, execution_fn.__name__)
Expand Down
28 changes: 14 additions & 14 deletions gpt_engineer/benchmark/benchmarks/gpteng/eval_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from tabulate import tabulate

from gpt_engineer.core.code import Code
from gpt_engineer.core.files_dict import FilesDict

EVAL_LIST_NAME = "evaluations" # the top level list in the YAML file

Expand All @@ -27,27 +27,27 @@ def check_language(eval_d: dict) -> None:
raise Exception(f"Language: {eval_d['language']} is not supported.")


def assert_exists_in_source_code(eval_d: dict, files: Code) -> bool:
def assert_exists_in_source_code(eval_d: dict, files_dict: FilesDict) -> bool:
"""Checks of some text exists in the source code."""
source_body = files[eval_d["source_file"]]
source_body = files_dict[eval_d["source_file"]]
return source_body.find(eval_d["existing_string"]) > -1


def run_code_class_has_property(eval_d: dict, files: Code) -> bool:
def run_code_class_has_property(eval_d: dict, files_dict: FilesDict) -> bool:
"""Will execute code, then check if the code has the desired proprty."""
check_language(eval_d)
source_body = files[eval_d["source_file"]]
source_body = files_dict[eval_d["source_file"]]
exec(source_body)

class_ref = locals().get(eval_d["class_name"])
ob = class_ref()
return hasattr(ob, eval_d["property_name"])


def run_code_class_has_property_w_value(eval_d: dict, files: Code) -> bool:
def run_code_class_has_property_w_value(eval_d: dict, files_dict: FilesDict) -> bool:
"""Will execute code, then check if the code has the desired proprty."""
check_language(eval_d)
source_body = files[eval_d["source_file"]]
source_body = files_dict[eval_d["source_file"]]
exec(source_body)

class_ref = locals().get(eval_d["class_name"])
Expand All @@ -58,28 +58,28 @@ def run_code_class_has_property_w_value(eval_d: dict, files: Code) -> bool:
return getattr(ob, eval_d["property_name"]) == eval_d["expected_value"]


def run_code_eval_function(eval_d: dict, files: Code) -> bool:
def run_code_eval_function(eval_d: dict, files_dict: FilesDict) -> bool:
"""Similar to run_code_class_has_property() except is evaluates a function call."""
check_language(eval_d)
source_body = files[eval_d["source_file"]]
source_body = files_dict[eval_d["source_file"]]
exec(source_body)
function_ref = globals().get(eval_d["function_name"])

# TODO: add the ability to have function arguments
return function_ref() == eval_d["expected_value"]


def check_evaluation_component(eval_d: dict, files: Code) -> bool:
def check_evaluation_component(eval_d: dict, files_dict: FilesDict) -> bool:
"""Switch on evaluation components"""
test_type = eval_d.get("type")
if test_type == "assert_exists_in_source_code":
return assert_exists_in_source_code(eval_d, files)
return assert_exists_in_source_code(eval_d, files_dict)
elif test_type == "run_code_class_has_property":
return run_code_class_has_property(eval_d, files)
return run_code_class_has_property(eval_d, files_dict)
elif test_type == "run_code_class_has_property_w_value":
return run_code_class_has_property_w_value(eval_d, files)
return run_code_class_has_property_w_value(eval_d, files_dict)
elif test_type == "run_code_eval_function":
return run_code_eval_function(eval_d, files)
return run_code_eval_function(eval_d, files_dict)
# The following are for new code
else:
raise Exception(f"Test type '{test_type}' is not recognized.")
Loading

0 comments on commit a3b7f88

Please sign in to comment.