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

Feature Improve CLI App #1154

Draft
wants to merge 42 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
bec7cff
ensure we have latest gpt-4-turbo model costs
TheoMcCabe Apr 18, 2024
cf689e7
hmm
TheoMcCabe Apr 18, 2024
d5d6104
get started
TheoMcCabe May 6, 2024
9d02097
Merge branch 'main' into lite
TheoMcCabe May 6, 2024
34b2f21
WIP
TheoMcCabe May 6, 2024
e9d00e4
Merge branch 'lite' of https://github.com/mynt-ai/gpt-engineer into lite
TheoMcCabe May 6, 2024
6e3bbdc
guess so
TheoMcCabe May 8, 2024
4c7a9b9
wip
TheoMcCabe May 9, 2024
ca15c7a
ye
TheoMcCabe May 9, 2024
3b5a782
rename files
TheoMcCabe May 12, 2024
6c8e9d8
add steps
TheoMcCabe May 12, 2024
8d9850c
improve runs
TheoMcCabe May 12, 2024
6470e30
linting pre commit
TheoMcCabe May 13, 2024
f43e288
wip
TheoMcCabe May 13, 2024
689a0c2
works with a task given
TheoMcCabe May 14, 2024
d91b373
update sub project
TheoMcCabe May 14, 2024
1693257
ignore feature
TheoMcCabe May 14, 2024
fe31d62
push tings
TheoMcCabe May 14, 2024
1398726
fix main cli app
TheoMcCabe May 14, 2024
eda60e0
basics
TheoMcCabe May 14, 2024
a5aea1a
remove prints
TheoMcCabe May 14, 2024
8643214
running to end
TheoMcCabe May 14, 2024
8977e8e
running in little loop
TheoMcCabe May 15, 2024
4ead7b1
Merge branch 'main' into lite
TheoMcCabe May 16, 2024
dd6daf6
wip
TheoMcCabe May 20, 2024
6b5ac55
Merge branch 'lite' of https://github.com/mynt-ai/gpt-engineer into lite
TheoMcCabe May 20, 2024
d20c786
wip -bad fuzzy matching
TheoMcCabe May 20, 2024
646a5bd
working to the end of first task
TheoMcCabe May 21, 2024
d9e2a40
basically working
TheoMcCabe May 21, 2024
f5e38fe
WIP
TheoMcCabe May 22, 2024
6525194
chat working
TheoMcCabe May 23, 2024
2704496
cool
TheoMcCabe May 23, 2024
802ec8a
wip
TheoMcCabe May 26, 2024
2142be4
roughly working
TheoMcCabe Jun 6, 2024
7ffc87e
WIP
TheoMcCabe Jun 6, 2024
319990a
working nicely
TheoMcCabe Jun 10, 2024
320588c
delete old one
TheoMcCabe Jun 10, 2024
e2da9c7
feature cli
TheoMcCabe Jun 11, 2024
d93ca36
hmmm
TheoMcCabe Jun 11, 2024
ddb5a1b
Merge branch 'main' into lite
TheoMcCabe Jun 11, 2024
59e4943
chat agent working
TheoMcCabe Jun 11, 2024
c216e6d
Merge branch 'lite' of https://github.com/mynt-ai/gpt-engineer into lite
TheoMcCabe Jun 11, 2024
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ webapp/.next/
gpt_engineer/benchmark/benchmarks/apps/dataset
gpt_engineer/benchmark/benchmarks/mbpp/dataset

prompt


.feature

gpt_engineer/benchmark/minimal_bench_config.toml

test.json
26 changes: 9 additions & 17 deletions gpt_engineer/applications/cli/file_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import fnmatch
import os
import platform
import subprocess

from pathlib import Path
Expand Down Expand Up @@ -225,32 +226,23 @@ def open_with_default_editor(self, file_path: Union[str, Path]):
The path to the file to be opened in the text editor.
"""

editors = [
"gedit",
"notepad",
"nvim",
"write",
"nano",
"vim",
"emacs",
] # Putting the beginner-friendly text editor forward
chosen_editor = os.environ.get("EDITOR")

# Try the preferred editor first, then fallback to common editors
if chosen_editor:
try:
subprocess.run([chosen_editor, file_path])
subprocess.run([chosen_editor, str(file_path)], check=True)
return
except Exception:
pass

for editor in editors:
try:
subprocess.run([editor, file_path])
return
except Exception:
continue
print("No suitable text editor found. Please edit the file manually.")
# Platform-specific methods to open the file
if platform.system() == "Windows":
os.startfile(file_path)
elif platform.system() == "Darwin":
subprocess.run(["open", file_path])
else: # Linux and other Unix-like systems
subprocess.run(["xdg-open", file_path])

def is_utf8(self, file_path: Union[str, Path]) -> bool:
"""
Expand Down
5 changes: 4 additions & 1 deletion gpt_engineer/applications/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,10 @@ def main(
if not no_execution:
if improve_mode:
files_dict_before = FileSelector(project_path).ask_for_files()
files_dict = handle_improve_mode(prompt, agent, memory, files_dict_before)

improve_lambda = lambda: agent.improve(files_dict_before, prompt)
files_dict = handle_improve_mode(improve_lambda, memory)

if not files_dict or files_dict_before == files_dict:
print(
f"No changes applied. Could you please upload the debug_log_file.txt in {memory.path}/logs folder in a github issue?"
Expand Down
72 changes: 72 additions & 0 deletions gpt_engineer/applications/interactive_cli/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from feature import Feature
from file_selection import FileSelection
from repository import Repository
from settings import Settings
from agent_steps import (
initialize_new_feature,
update_user_file_selection,
check_for_unstaged_changes,
confirm_feature_context_and_task_with_user,
run_task_loop,
adjust_feature_task_or_files,
update_task_description,
)

from gpt_engineer.core.ai import AI
from gpt_engineer.core.base_agent import BaseAgent


class FeatureAgent(BaseAgent):
"""
A cli agent which implements a feature as a set of incremental tasks
"""

def __init__(
self,
project_path: str,
feature: Feature,
repository: Repository,
ai: AI = None,
):
self.project_path = project_path
self.feature = feature
self.repository = repository
self.ai = ai or AI()

self.file_selection = FileSelection(project_path, repository)

def init(self, settings: Settings):

initialize_new_feature(
self.ai, self.feature, self.repository, settings.no_branch
)

update_user_file_selection(self.file_selection)

update_task_description(self.feature)

self.resume(settings)

def resume(self, settings: Settings):

implement = False

while not implement:
implement = confirm_feature_context_and_task_with_user(
self.feature, self.file_selection
)

adjust_feature_task_or_files()

check_for_unstaged_changes(self.repository)

run_task_loop(
self.project_path,
self.feature,
self.repository,
self.ai,
self.file_selection,
)

def improve(self):
self.resume()
195 changes: 195 additions & 0 deletions gpt_engineer/applications/interactive_cli/agent_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
from feature import Feature
from file_selection import FileSelection
from repository import Repository
from files import Files
from generation_tools import generate_branch_name, build_context_string
from termcolor import colored

from gpt_engineer.core.ai import AI
from gpt_engineer.core.prompt import Prompt
from gpt_engineer.core.default.steps import improve_fn, handle_improve_mode
from gpt_engineer.core.default.disk_memory import DiskMemory
from gpt_engineer.core.default.paths import PREPROMPTS_PATH, memory_path
from gpt_engineer.core.preprompts_holder import PrepromptsHolder
from gpt_engineer.core.prompt import Prompt

from prompt_toolkit import prompt as cli_input
from prompt_toolkit.validation import ValidationError, Validator
from prompt_toolkit import PromptSession as InputSession
from prompt_toolkit.completion import WordCompleter


class FeatureValidator(Validator):
def validate(self, document):
text = document.text
if not text:
raise ValidationError(
message="Feature description cannot be empty", cursor_position=len(text)
)


def initialize_new_feature(
ai: AI, feature: Feature, repository: Repository, no_branch: bool
):
feature.clear_feature()

update_feature_description(feature)

branch_name = generate_branch_name(ai, feature.get_description())

branch_name = cli_input("\nConfirm branch name: ", default=branch_name)

if not no_branch:
repository.create_branch(branch_name)
print("\nFeature branch created.\n")


def update_user_file_selection(file_selection: FileSelection):
file_selection.update_yaml_from_tracked_files()
file_selection.open_yaml_in_editor()
input(
"Please edit the file selection for this feature and then press Enter to continue..."
)


def update_feature_description(feature: Feature):
feature.open_feature_in_editor()
input("Please edit the feature file and then press Enter to continue...")


def update_task_description(feature: Feature):
feature.open_task_in_editor()
input("Please edit the task file and then press Enter to continue...")


def check_for_unstaged_changes(
repository: Repository,
):
git_context = repository.get_git_context()

if git_context.unstaged_changes:
if input(
"Unstaged changes present are you sure you want to proceed? y/n"
).lower() not in ["", "y", "yes"]:
print("Ok, not proceeding.")
return


def confirm_feature_context_and_task_with_user(
feature: Feature, file_selection: FileSelection
):
file_selection.update_yaml_from_tracked_files()
file_string = file_selection.get_pretty_from_yaml()

feature_description = feature.get_description()
task = feature.get_task()

# list feature, files and task
print(f"Feature: {feature_description}\n\n")
print(f"Files: \n\nrepo\n{file_string}\n\n")
print(f"Task: {task}\n\n")

# do you want to attempt this task?
if cli_input("Do you want to implement this task? y/n: ").lower() in [
"y",
"yes",
]:
return True

return False


def complete_task():
pass

# feature.complete task
# then


def adjust_feature_task_or_files():
pass
# todo : create a function which uses the test4.py example code approach to offer a selection of options to the user

# c - complete the task and start a new one

# f - "edit feature" using update_feature_description step
# s - "edit file selection" using update_user_file_selection step
# t - "edit task" using update_task_description step

#


def run_task_loop(
project_path,
feature: Feature,
repository: Repository,
ai: AI,
file_selection: FileSelection,
):

memory = DiskMemory(memory_path(project_path))
preprompts_holder = PrepromptsHolder(PREPROMPTS_PATH)

context_string = build_context_string(feature, repository.get_git_context())

prompt = Prompt(feature.get_task(), prefix="Task: ")

files = Files(project_path, file_selection.get_from_yaml())

improve_lambda = lambda: improve_fn(
ai, prompt, files, memory, preprompts_holder, context_string
)

print("\n---- begining code generation ----\n")
updated_files_dictionary = handle_improve_mode(improve_lambda, memory)
print("\n---- ending code generation ----\n")

files.write_to_disk(updated_files_dictionary)

review_changes(project_path, feature, repository, ai, file_selection)


def review_changes(
project_path,
feature: Feature,
repository: Repository,
ai: AI,
file_selection: FileSelection,
):

completer = WordCompleter(["r", "c", "u"], ignore_case=True)
session = InputSession()

# Using prompt to get user input
result = session.prompt(
"""Please review the unstaged changes generated by GPT Engineer..

r: Delete and retry the generation (incorporating changes to prompt files)
c: Complete task and stage changes
u: Undo changes and exit
""",
completer=completer,
).lower()

if result == "r":
print("Deleting changes and rerunning generation...")
repository.undo_unstaged_changes()
run_task_loop(project_path, feature, repository, ai, file_selection)

if result == "c":
print("Completing task... ")
repository.stage_all_changes()
feature.complete_task()
file_selection.update_yaml_from_tracked_files()
if cli_input("Do you want to start a new task? y/n: ").lower() in [
"y",
"yes",
]:
update_task_description(feature)
run_task_loop(project_path, feature, repository, ai, file_selection)
return

if result == "u":
print("Undo the last operation.")
repository.undo_unstaged_changes()
return
Loading
Loading