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

fix skip_step #359

Merged
merged 2 commits into from
Dec 11, 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: 1 addition & 0 deletions pilot/helpers/AgentConvo.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def send_message(self, prompt_path=None, prompt_data=None, function_calls: Funct
else:
# if we don't, get the response from LLM
try:
self.agent.project.skip_steps = False # todo this is quick fix for flag that shows if we fully loaded project, should be implemented properly
self.replace_files()
response = create_gpt_chat_completion(self.messages, self.high_level_step, self.agent.project,
function_calls=function_calls)
Expand Down
9 changes: 5 additions & 4 deletions pilot/helpers/Project.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def __init__(self, args, name=None, project_description=None, clarifications=Non
self.skip_steps = None
self.main_prompt = None
self.files = []
self.continuing_project = args.get('continuing_project', False)

self.ipc_client_instance = ipc_client_instance

Expand Down Expand Up @@ -268,11 +269,11 @@ def save_file(self, data):
if not self.skip_steps:
inputs_required = self.find_input_required_lines(data['content'])
for line_number, line_content in inputs_required:
user_input = ''
user_input = None
print(color_yellow_bold(f'Input required on line {line_number}:\n{line_content}') + '\n')
while user_input.lower() not in AFFIRMATIVE_ANSWERS:
print({'path': data['path'], 'line': line_number}, type='openFile')
print('yes', type='button')
while user_input is None or user_input.lower() not in AFFIRMATIVE_ANSWERS + ['continue']:
print({'path': full_path, 'line': line_number}, type='openFile')
print('continue', type='button')
user_input = styled_text(
self,
f'Please open the file {data["path"]} on the line {line_number} and add the required input. Once you\'re done, type "y" to continue.',
Expand Down
83 changes: 45 additions & 38 deletions pilot/helpers/agents/Developer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from utils.utils import should_execute_step, array_of_objects_to_string, generate_app_data
from helpers.cli import run_command_until_success, execute_command_and_check_cli_response, running_processes
from const.function_calls import FILTER_OS_TECHNOLOGIES, EXECUTE_COMMANDS, GET_TEST_TYPE, IMPLEMENT_TASK, \
COMMAND_TO_RUN, GET_MISSING_SNIPPETS, GET_FULLY_CODED_FILE
COMMAND_TO_RUN, GET_FULLY_CODED_FILE
from database.database import save_progress, get_progress_steps, update_app_status
from utils.utils import get_os_info

Expand All @@ -44,7 +44,7 @@ def start_coding(self):
update_app_status(self.project.args['app_id'], self.project.current_step)

if self.project.skip_steps is None:
self.project.skip_steps = False if ('skip_until_dev_step' in self.project.args and self.project.args['skip_until_dev_step'] == '0') else True
self.project.skip_steps = False if (not self.project.continuing_project or ('skip_until_dev_step' in self.project.args and self.project.args['skip_until_dev_step'] == '0')) else True

# DEVELOPMENT
print(color_green_bold("🚀 Now for the actual development...\n"))
Expand Down Expand Up @@ -110,20 +110,20 @@ def implement_task(self, i, development_task=None):

while True:
result = self.execute_task(convo_dev_task,
development_task['description'],
steps,
development_task=development_task,
continue_development=True,
is_root_task=True,
continue_from_step=len(completed_steps))
development_task['description'],
steps,
development_task=development_task,
continue_development=True,
is_root_task=True,
continue_from_step=len(completed_steps))

if result['success']:
break

if 'step_index' in result:
result['os'] = platform.system()
step_index = result['step_index']
completed_steps = steps[:step_index+1]
completed_steps = steps[:step_index + 1]
result['completed_steps'] = completed_steps
result['current_step'] = steps[step_index]
result['next_steps'] = steps[step_index + 1:]
Expand All @@ -144,10 +144,11 @@ def replace_old_code_comments(self, files_with_changes):
for file in files_with_comments:
if len(file['comments']) > 0:
fully_coded_file_convo = AgentConvo(self)
fully_coded_file_response = fully_coded_file_convo.send_message('development/get_fully_coded_file.prompt', {
'file': self.project.get_files([file['path']])[0],
'new_file': file,
}, GET_FULLY_CODED_FILE)
fully_coded_file_response = fully_coded_file_convo.send_message(
'development/get_fully_coded_file.prompt', {
'file': self.project.get_files([file['path']])[0],
'new_file': file,
}, GET_FULLY_CODED_FILE)

file['content'] = fully_coded_file_response['file_content']

Expand All @@ -158,11 +159,12 @@ def step_code_change(self, convo, task_description, step, i, test_after_code_cha
# TODO this should be refactored so it always uses the same function call
print(f'Implementing code changes for `{step["code_change_description"]}`')
code_monkey = CodeMonkey(self.project, self)
updated_convo = code_monkey.implement_code_changes(convo, task_description, step['code_change_description'], step, i)
updated_convo = code_monkey.implement_code_changes(convo, task_description, step['code_change_description'],
step, i)
if test_after_code_changes:
return self.test_code_changes(code_monkey, updated_convo)
else:
return { "success": True }
return {"success": True}

# TODO fix this - the problem is in GPT response that sometimes doesn't return the correct JSON structure
if 'code_change' not in step:
Expand All @@ -184,7 +186,7 @@ def step_command_run(self, convo, step, i, success_with_cli_response=False):
else:
data = step['command']
# TODO END
additional_message = '' #'Let\'s start with the step #0:\n' if i == 0 else f'So far, steps { ", ".join(f"#{j}" for j in range(i+1)) } are finished so let\'s do step #{i + 1} now.\n'
additional_message = '' # 'Let\'s start with the step #0:\n' if i == 0 else f'So far, steps { ", ".join(f"#{j}" for j in range(i+1)) } are finished so let\'s do step #{i + 1} now.\n'

command_id = data['command_id'] if 'command_id' in data else None
success_message = data['success_message'] if 'success_message' in data else None
Expand Down Expand Up @@ -245,8 +247,8 @@ def step_human_intervention(self, convo, step: dict):
response['success'] = True
else:
response['success'] = self.debugger.debug(convo,
user_input=response['user_input'],
issue_description=step['human_intervention_description'])
user_input=response['user_input'],
issue_description=step['human_intervention_description'])
# TODO add review

return response
Expand All @@ -255,7 +257,7 @@ def step_test(self, convo, test_command):
# TODO: don't re-run if it's already running
should_rerun_command = convo.send_message('dev_ops/should_rerun_command.prompt', test_command)
if should_rerun_command == 'NO':
return { 'success': True }
return {'success': True}
elif should_rerun_command == 'YES':
logger.info('Re-running test command: %s', test_command)
cli_response, llm_response = execute_command_and_check_cli_response(convo, test_command)
Expand Down Expand Up @@ -332,14 +334,15 @@ def should_retry_step_implementation(self, step, step_implementation_try):
if answer == 'n':
return self.dev_help_needed(step)

return { "success": False, "retry": True }
return {"success": False, "retry": True}

def dev_help_needed(self, step):

if step['type'] == 'command':
help_description = (color_red_bold('I tried running the following command but it doesn\'t seem to work:\n\n') +
color_white_bold(step['command']['command']) +
color_red_bold('\n\nCan you please make it work?'))
help_description = (
color_red_bold('I tried running the following command but it doesn\'t seem to work:\n\n') +
color_white_bold(step['command']['command']) +
color_red_bold('\n\nCan you please make it work?'))
elif step['type'] == 'code_change':
help_description = step['code_change_description']
elif step['type'] == 'human_intervention':
Expand All @@ -354,6 +357,7 @@ def extract_substring(s):
return s[start_idx + 3:end_idx]
else:
return s

# TODO end

answer = ''
Expand All @@ -368,7 +372,7 @@ def extract_substring(s):
)
logger.info("help needed: %s", answer)

return { "success": True, "user_input": answer }
return {"success": True, "user_input": answer}

def execute_task(self, convo, task_description, task_steps, test_command=None, reset_convo=True,
test_after_code_changes=True, continue_development=False,
Expand Down Expand Up @@ -441,7 +445,7 @@ def execute_task(self, convo, task_description, task_steps, test_command=None, r
else:
raise e

result = { "success": True } # if all steps are finished, the task has been successfully implemented
result = {"success": True} # if all steps are finished, the task has been successfully implemented
convo.load_branch(function_uuid)
return self.task_postprocessing(convo, development_task, continue_development, result, function_uuid)

Expand All @@ -450,13 +454,15 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr
logger.info('Continue development, last_branch_name: %s', last_branch_name)
if last_branch_name in iteration_convo.branches.keys(): # if user_feedback is not None we create new convo
iteration_convo.load_branch(last_branch_name)
user_description = ('Here is a description of what should be working: \n\n' + color_cyan_bold(continue_description) + '\n') \
if continue_description != '' else ''
user_description = ('Here is a description of what should be working: \n\n' + color_cyan_bold(
continue_description) + '\n') \
if continue_description != '' else ''
user_description = 'Can you check if the app works please? ' + user_description

if self.run_command:
if self.project.ipc_client_instance is None or self.project.ipc_client_instance.client is None:
user_description += color_yellow_bold('\n\nIf you want to run the app, just type "r" and press ENTER and that will run `' + self.run_command + '`')
user_description += color_yellow_bold(
'\n\nIf you want to run the app, just type "r" and press ENTER and that will run `' + self.run_command + '`')
else:
print(self.run_command, type='run_command')

Expand All @@ -479,7 +485,7 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr
logger.info('response: %s', response)
user_feedback = response['user_input'] if 'user_input' in response else None
if user_feedback == 'continue':
return { "success": True, "user_input": user_feedback }
return {"success": True, "user_input": user_feedback}

if user_feedback is not None:
iteration_convo = AgentConvo(self)
Expand Down Expand Up @@ -508,7 +514,6 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr
task_steps = llm_response['tasks']
self.execute_task(iteration_convo, iteration_description, task_steps, is_root_task=True)


def set_up_environment(self):
self.project.current_step = ENVIRONMENT_SETUP_STEP
self.convo_os_specific_tech = AgentConvo(self)
Expand All @@ -524,7 +529,9 @@ def set_up_environment(self):
print('done', type='button')
user_input = styled_text(self.project, 'Please set up your local environment so that the technologies listed can be utilized. When you\'re done, write "DONE"')
save_progress(self.project.args['app_id'], self.project.current_step, {
"os_specific_technologies": [], "newly_installed_technologies": [], "app_data": generate_app_data(self.project.args)
"os_specific_technologies": [],
"newly_installed_technologies": [],
"app_data": generate_app_data(self.project.args)
})
return
# ENVIRONMENT SETUP
Expand All @@ -533,12 +540,12 @@ def set_up_environment(self):

os_info = get_os_info()
llm_response = self.convo_os_specific_tech.send_message('development/env_setup/specs.prompt',
{
"name": self.project.args['name'],
"app_type": self.project.args['app_type'],
"os_info": os_info,
"technologies": self.project.architecture
}, FILTER_OS_TECHNOLOGIES)
{
"name": self.project.args['name'],
"app_type": self.project.args['app_type'],
"os_info": os_info,
"technologies": self.project.architecture
}, FILTER_OS_TECHNOLOGIES)

os_specific_technologies = llm_response['technologies']
for technology in os_specific_technologies:
Expand Down Expand Up @@ -601,7 +608,7 @@ def install_technology(self, technology):
return llm_response

def test_code_changes(self, code_monkey, convo):
return { "success": True }
return {"success": True}
logger.info('Testing code changes...')
llm_response = convo.send_message('development/task/step_check.prompt', {}, GET_TEST_TYPE)
test_type = llm_response['type']
Expand Down
6 changes: 5 additions & 1 deletion pilot/utils/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ def get_arguments():
args = sys.argv[1:]

# Create an empty dictionary to store the key-value pairs.
arguments = {}
arguments = {
'continuing_project': False
}

# Loop through the arguments and parse them as key-value pairs.
for arg in args:
Expand All @@ -39,6 +41,7 @@ def get_arguments():
app = get_app_by_user_workspace(arguments['user_id'], arguments['workspace'])
if app is not None:
arguments['app_id'] = str(app.id)
arguments['continuing_project'] = True
else:
arguments['workspace'] = None

Expand All @@ -49,6 +52,7 @@ def get_arguments():
arguments['app_type'] = app.app_type
arguments['name'] = app.name
arguments['status'] = app.status
arguments['continuing_project'] = True
if 'step' not in arguments or ('step' in arguments and not should_execute_step(arguments['step'], app.status)):
arguments['step'] = 'finished' if app.status == 'finished' else STEPS[STEPS.index(app.status) + 1]

Expand Down