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

Naming suggestions #887

Merged
merged 6 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading