Skip to content

Commit

Permalink
Merge pull request #360 from Pythagora-io/development
Browse files Browse the repository at this point in the history
Development merge
  • Loading branch information
LeonOstrez authored Dec 11, 2023
2 parents fb5fbd7 + 1114209 commit 0d6cda3
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 43 deletions.
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

0 comments on commit 0d6cda3

Please sign in to comment.