From ba3fe76168cdcc219204d4960c601ac1b9ac3147 Mon Sep 17 00:00:00 2001 From: LeonOstrez Date: Mon, 11 Dec 2023 17:25:24 +0000 Subject: [PATCH 1/2] fix skip_step --- pilot/helpers/AgentConvo.py | 1 + pilot/helpers/Project.py | 9 ++-- pilot/helpers/agents/Developer.py | 83 +++++++++++++++++-------------- pilot/utils/arguments.py | 6 ++- 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/pilot/helpers/AgentConvo.py b/pilot/helpers/AgentConvo.py index 76ba5a346..9d8f5c929 100644 --- a/pilot/helpers/AgentConvo.py +++ b/pilot/helpers/AgentConvo.py @@ -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) diff --git a/pilot/helpers/Project.py b/pilot/helpers/Project.py index 45cb62973..d15b074ba 100644 --- a/pilot/helpers/Project.py +++ b/pilot/helpers/Project.py @@ -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['continuing_project'] self.ipc_client_instance = ipc_client_instance @@ -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.', diff --git a/pilot/helpers/agents/Developer.py b/pilot/helpers/agents/Developer.py index 822393665..7dc784953 100644 --- a/pilot/helpers/agents/Developer.py +++ b/pilot/helpers/agents/Developer.py @@ -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 @@ -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")) @@ -110,12 +110,12 @@ 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 @@ -123,7 +123,7 @@ def implement_task(self, i, development_task=None): 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:] @@ -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'] @@ -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: @@ -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 @@ -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 @@ -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) @@ -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': @@ -354,6 +357,7 @@ def extract_substring(s): return s[start_idx + 3:end_idx] else: return s + # TODO end answer = '' @@ -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, @@ -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) @@ -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') @@ -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) @@ -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) @@ -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 @@ -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: @@ -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'] diff --git a/pilot/utils/arguments.py b/pilot/utils/arguments.py index 4a9bd2b6f..7545a46cf 100644 --- a/pilot/utils/arguments.py +++ b/pilot/utils/arguments.py @@ -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: @@ -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 @@ -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] From 412520c939051781a4767791c80aefa25e2ed6fe Mon Sep 17 00:00:00 2001 From: LeonOstrez Date: Mon, 11 Dec 2023 17:31:29 +0000 Subject: [PATCH 2/2] fix getting argument --- pilot/helpers/Project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pilot/helpers/Project.py b/pilot/helpers/Project.py index d15b074ba..545f75386 100644 --- a/pilot/helpers/Project.py +++ b/pilot/helpers/Project.py @@ -60,7 +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['continuing_project'] + self.continuing_project = args.get('continuing_project', False) self.ipc_client_instance = ipc_client_instance