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

adding advanced options to cli #851

Merged
merged 6 commits into from
Nov 16, 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
1 change: 0 additions & 1 deletion gpt_engineer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
domain,
chat_to_files,
)
from gpt_engineer.legacy import steps
from gpt_engineer.tools import code_vector_repository
from gpt_engineer.core.default import on_disk_repository
29 changes: 24 additions & 5 deletions gpt_engineer/applications/cli/cli_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@
from gpt_engineer.core.default.paths import memory_path, ENTRYPOINT_FILE
from gpt_engineer.core.base_agent import BaseAgent
from gpt_engineer.applications.cli.learning import human_review
from typing import TypeVar, Callable

CodeGenType = TypeVar(
"CodeGenType", bound=Callable[[AI, str, BaseRepository], Code]
)
ExecuteEntrypointType = TypeVar(
"ExecuteEntrypointType", bound=Callable[[AI, BaseExecutionEnv, Code], None]
)
ImproveType = TypeVar(
"ImproveType", bound=Callable[[AI, str, Code, BaseRepository], Code]
)

class CliAgent(BaseAgent):
"""
Expand Down Expand Up @@ -62,32 +72,41 @@ def __init__(
memory: BaseRepository,
execution_env: BaseExecutionEnv,
ai: AI = None,
code_gen_fn: CodeGenType = gen_code,
execute_entrypoint_fn: ExecuteEntrypointType = execute_entrypoint,
improve_fn: ImproveType = improve
):
self.memory = memory
self.execution_env = execution_env
self.ai = ai or AI()
self.code_gen_fn = code_gen_fn
self.execute_entrypoint_fn = execute_entrypoint_fn
self.improve_fn = improve_fn

@classmethod
def with_default_config(cls, path: str, ai: AI = None):
def with_default_config(cls, path: str, ai: AI = None, code_gen_fn: CodeGenType = gen_code, execute_entrypoint_fn: ExecuteEntrypointType = execute_entrypoint, improve_fn: ImproveType = improve):
return cls(
memory=OnDiskRepository(memory_path(path)),
execution_env=OnDiskExecutionEnv(path),
ai=ai,
code_gen_fn=code_gen_fn,
execute_entrypoint_fn=execute_entrypoint_fn,
improve_fn=improve_fn
)

def init(self, prompt: str) -> Code:
code = gen_code(self.ai, prompt, self.memory)
code = self.code_gen_fn(self.ai, prompt, self.memory)
entrypoint = gen_entrypoint(self.ai, code, self.memory)
code = Code(code | entrypoint)
execute_entrypoint(self.execution_env, code)
self.execute_entrypoint_fn(self.ai, self.execution_env, code)
human_review(self.memory)
return code

def improve(self, prompt: str, code: Code) -> Code:
code = improve(self.ai, prompt, code)
code = self.improve_fn(self.ai, prompt, code, self.memory)
if not ENTRYPOINT_FILE in code:
entrypoint = gen_entrypoint(self.ai, code, self.memory)
code = Code(code | entrypoint)
execute_entrypoint(self.execution_env, code)
self.execute_entrypoint_fn(self.ai, self.execution_env, code)
human_review(self.memory)
return code
39 changes: 29 additions & 10 deletions gpt_engineer/applications/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@
from gpt_engineer.core.ai import AI
from gpt_engineer.core.code import Code
from gpt_engineer.applications.cli.file_selector import ask_for_files

# from gpt_engineer.legacy.steps import STEPS, Config as StepsConfig
# from gpt_engineer.applications.cli.collect import collect_learnings
# from gpt_engineer.applications.cli.learning import check_collection_consent
# from gpt_engineer.tools.code_vector_repository import CodeVectorRepository
from gpt_engineer.tools.custom_steps import lite_gen, gen_clarified_code, self_heal
from gpt_engineer.core.default.steps import gen_code, execute_entrypoint
from gpt_engineer.applications.cli.cli_agent import CliAgent


Expand Down Expand Up @@ -86,9 +83,6 @@ def main(
project_path: str = typer.Argument("projects/example", help="path"),
model: str = typer.Argument("gpt-4-1106-preview", help="model id string"),
temperature: float = 0.1,
# steps_config: StepsConfig = typer.Option(
# StepsConfig.DEFAULT, "--steps", "-s", help="decide which steps to run"
# ),
improve_mode: bool = typer.Option(
False,
"--improve",
Expand All @@ -107,6 +101,18 @@ def main(
"-l",
help="Lite mode - run only the main prompt.",
),
clarify_mode: bool = typer.Option(
False,
"--clarify",
"-c",
help="Lite mode - discuss specification with AI before implementation.",
),
self_heal_mode: bool = typer.Option(
False,
"--self-heal",
"-sh",
help="Lite mode - discuss specification with AI before implementation.",
),
azure_endpoint: str = typer.Option(
"",
"--azure",
Expand Down Expand Up @@ -153,9 +159,22 @@ def main(
# project_path
# ) # 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, "\n")
print("Running gpt-engineer in", path.absolute(), "\n")
prompt = load_prompt(OnDiskRepository(path))
agent = CliAgent.with_default_config(project_path)
# configure generation function
if clarify_mode:
code_gen_fn = gen_clarified_code
elif lite_mode:
code_gen_fn = lite_gen
else:
code_gen_fn = gen_code
# configure execution function
if self_heal_mode:
execution_fn = self_heal
else:
execution_fn = execute_entrypoint

agent = CliAgent.with_default_config(project_path, code_gen_fn=code_gen_fn, execute_entrypoint_fn=execution_fn)
if improve_mode:
code = ask_for_files(project_path)
agent.improve(prompt, code)
Expand Down
1 change: 1 addition & 0 deletions gpt_engineer/core/chat_to_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def parse_chat(chat) -> List[Tuple[str, str]]:
# files.append(("README.md", readme))

# Return the files
# ToDo: Directly return code object
return files


Expand Down
10 changes: 10 additions & 0 deletions gpt_engineer/core/default/git_version_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@


class GitVersionManager(BaseVersionManager):
"""
Manages versions of code using Git as the version control system.

This class is responsible for creating snapshots of the code, which typically involves
saving the code to a file and committing it to a Git repository. The snapshot method
returns a unique hash that can be used to identify the version of the code.

Attributes:
path (str): The file system path where the Git repository is located.
"""
def __init__(self, path: str):
self.path = path

Expand Down
14 changes: 13 additions & 1 deletion gpt_engineer/core/default/lean_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@


class LeanAgent(BaseAgent):
"""
An agent that uses AI to generate and improve code based on a given prompt.

This agent is capable of initializing a codebase from a prompt and improving an existing
codebase based on user input. It uses an AI model to generate and refine code, and it
interacts with a repository and an execution environment to manage and execute the code.

Attributes:
memory (BaseRepository): The repository where the code and related data are stored.
execution_env (BaseExecutionEnv): The environment in which the code is executed.
ai (AI): The AI model used for generating and improving code.
"""
def __init__(
self,
memory: BaseRepository,
Expand All @@ -40,7 +52,7 @@ def init(self, prompt: str) -> Code:
return code

def improve(self, prompt: str, code: Code) -> Code:
code = improve(self.ai, prompt, code)
code = improve(self.ai, prompt, code, self.memory)
if not ENTRYPOINT_FILE in code:
entrypoint = gen_entrypoint(self.ai, code, self.memory)
code = Code(code | entrypoint)
Expand Down
14 changes: 12 additions & 2 deletions gpt_engineer/core/default/on_disk_execution_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@


class OnDiskExecutionEnv(BaseExecutionEnv):
"""
An execution environment that runs code on the local file system.

This class is responsible for executing code that is stored on disk. It ensures that
the necessary entrypoint file exists and then runs the code using a subprocess. If the
execution is interrupted by the user, it handles the interruption gracefully.

Attributes:
path (str): The file system path where the code is located and will be executed.
"""
def __init__(self, path: str):
self.path = path

Expand All @@ -16,12 +26,12 @@ def execute_program(self, code: Code) -> subprocess.Popen:
+ ENTRYPOINT_FILE
+ " does not exist in the code."
)

# ToDo: The fact that execution is the de-facto way of saving the code to disk presently should change once version manager is implemented.
workspace = OnDiskRepository(self.path)
for file_name, file_content in code.items():
workspace[file_name] = file_content

p = subprocess.Popen("bash " + ENTRYPOINT_FILE, shell=True, cwd=self.path)
p = subprocess.Popen("bash " + ENTRYPOINT_FILE, shell=True, cwd=self.path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
try:
p.wait()
except KeyboardInterrupt:
Expand Down
35 changes: 35 additions & 0 deletions gpt_engineer/core/default/on_disk_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ class OnDiskRepository(BaseRepository):
facilitate CRUD-like interactions. It allows for quick checks on the existence of keys,
retrieval of values based on keys, and setting new key-value pairs.

Attributes:
path (Path): The directory path where the database files are stored.
"""
"""
A file-based key-value store where keys correspond to filenames and values to file contents.

This class provides an interface to a file-based database, leveraging file operations to
facilitate CRUD-like interactions. It allows for quick checks on the existence of keys,
retrieval of values based on keys, and setting new key-value pairs.

Attributes
----------
path : Path
Expand Down Expand Up @@ -228,6 +238,21 @@ def to_path_list_string(self, supported_code_files_only: bool = False) -> str:
# dataclass for all dbs:
# @dataclass
class FileRepositories:
"""
Encapsulates multiple file-based repositories representing different aspects of a project.

This class holds references to various repositories used for storing different types of
data, such as memory, logs, preprompts, input, workspace, archive, and project metadata.

Attributes:
memory (BaseRepository): The repository for storing memory-related data.
logs (BaseRepository): The repository for storing log files.
preprompts (BaseRepository): The repository for storing preprompt data.
input (BaseRepository): The repository for storing input data.
workspace (BaseRepository): The repository representing the workspace.
archive (BaseRepository): The repository for archiving data.
project_metadata (BaseRepository): The repository for storing project metadata.
"""
memory: BaseRepository
logs: BaseRepository
preprompts: BaseRepository
Expand All @@ -238,6 +263,16 @@ class FileRepositories:


def archive(dbs: FileRepositories) -> None:
"""
Archives the contents of memory and workspace repositories.

This function moves the contents of the memory and workspace repositories to the archive
repository, organizing them with a timestamp. It is used to preserve the state of these
repositories at a specific point in time.

Parameters:
dbs (FileRepositories): The collection of repositories to be archived.
"""
"""
Archive the memory and workspace databases.

Expand Down
1 change: 1 addition & 0 deletions gpt_engineer/core/default/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
META_DATA_REL_PATH = ".gpteng"
MEMORY_REL_PATH = os.path.join(META_DATA_REL_PATH, "memory")
CODE_GEN_LOG_FILE = "all_output.txt"
IMPROVE_LOG_FILE = "improve.txt"
ENTRYPOINT_FILE = "run.sh"
ENTRYPOINT_LOG_FILE = "gen_entrypoint_chat.txt"

Expand Down
Loading
Loading