Skip to content

Commit

Permalink
Merge pull request Pythagora-io#693 from Pythagora-io/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
senko authored Mar 2, 2024
2 parents 30e2137 + 4c632a8 commit 80a73c0
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 58 deletions.
4 changes: 2 additions & 2 deletions pilot/const/messages.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CHECK_AND_CONTINUE = 'Is everything working? Let me know if something needs to be changed for this task or type "continue" to proceed.'
WHEN_USER_DONE = 'Once you have completed, enter "continue"'
AFFIRMATIVE_ANSWERS = ['', 'y', 'yes', 'ok', 'okay', 'sure', 'absolutely', 'indeed', 'correct', 'affirmative', 'Use GPT Pilot\'s code']
NEGATIVE_ANSWERS = ['n', 'no', 'skip', 'negative', 'not now', 'cancel', 'decline', 'stop', 'Keep my changes']
AFFIRMATIVE_ANSWERS = ['', 'y', 'yes', 'ok', 'okay', 'sure', 'absolutely', 'indeed', 'correct', 'affirmative']
NEGATIVE_ANSWERS = ['n', 'no', 'skip', 'negative', 'not now', 'cancel', 'decline', 'stop']
STUCK_IN_LOOP = 'I\'m stuck in loop'
NONE_OF_THESE = 'none of these'
MAX_PROJECT_NAME_LENGTH = 50
4 changes: 2 additions & 2 deletions pilot/database/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def save_command_run(project, command, cli_response, done_or_error_response, exi
unique_data = {
'app': project.args['app_id'],
'previous_step': project.checkpoints['last_command_run'],
'high_level_step': project.current_step,
'high_level_step': str(project.checkpoints['last_development_step']['id']) if project.checkpoints['last_development_step'] else None,
}

data_fields = {
Expand All @@ -391,7 +391,7 @@ def save_user_input(project, query, user_input, hint):
unique_data = {
'app': project.args['app_id'],
'previous_step': project.checkpoints['last_user_input'],
'high_level_step': project.current_step,
'high_level_step': str(project.checkpoints['last_development_step']['id']) if project.checkpoints['last_development_step'] else None,
}
data_fields = {
'query': query,
Expand Down
47 changes: 32 additions & 15 deletions pilot/helpers/Project.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

from utils.telemetry import telemetry
from utils.task import Task
from utils.utils import remove_lines_with_string, is_extension_old_version
from utils.utils import remove_lines_with_string


class Project:
Expand All @@ -58,8 +58,6 @@ def __init__(
current_step (str, optional): Current step in the project. Default is None.
"""
self.args = args
# TODO remove everything related to is_extension_old_version once new version is released and everybody has to update core
self.is_extension_old_version = is_extension_old_version(args)
self.llm_req_num = 0
self.command_runs_count = 0
self.user_inputs_count = 0
Expand Down Expand Up @@ -98,7 +96,7 @@ def __init__(
File.update_paths()

# start loading of project (since backwards compatibility)
self.should_overwrite_files = False
self.should_overwrite_files = None
self.last_detailed_user_review_goal = None
self.last_iteration = None
self.tasks_to_load = []
Expand All @@ -118,22 +116,41 @@ def setup_loading(self):
return

self.skip_steps = True
should_overwrite_files = None
while should_overwrite_files is None or should_overwrite_files.lower() not in AFFIRMATIVE_ANSWERS + NEGATIVE_ANSWERS:
print('Use GPT Pilot\'s code/Keep my changes', type='buttons-only')
should_overwrite_files = styled_text(
while self.should_overwrite_files is None:
changes_made_question = f'Did you make any changes to "{self.args["name"]}" project files since last time you used Pythagora?'
print(changes_made_question, type='ipc', category='pythagora')
print('yes/no', type='buttons-only')
# must use styled_text() instead of ask_user() here to avoid finish_loading() call
changes_made = styled_text(
self,
"Can GPT Pilot overwrite code changes you made since last running GPT Pilot?",
ignore_user_input_count=True
changes_made_question,
ignore_user_input_count=True,
)

logger.info('should_overwrite_files: %s', should_overwrite_files)
if should_overwrite_files in NEGATIVE_ANSWERS:
self.should_overwrite_files = False
break
elif should_overwrite_files in AFFIRMATIVE_ANSWERS:
# if there were no changes just load files from db
if changes_made.lower() in NEGATIVE_ANSWERS:
self.should_overwrite_files = True
break
# otherwise ask user if they want to use those changes
elif changes_made.lower() in AFFIRMATIVE_ANSWERS:
use_changes_question = 'Do you want to use those changes you made?'
use_changes_msg = 'yes'
dont_use_changes_msg = 'no, restore last pythagora state'
print(use_changes_question, type='ipc', category='pythagora')
print(f'{use_changes_msg}/{dont_use_changes_msg}', type='buttons-only')
print(f'"{dont_use_changes_msg}" means Pythagora will restore (overwrite) all files to last stored state.\n'
f'"{use_changes_msg}" means Pythagora will continue working on project using current state of files.', type='hint')
use_changes = styled_text(
self,
use_changes_question,
ignore_user_input_count=True
)

logger.info('Use changes: %s', use_changes)
if use_changes.lower() in NEGATIVE_ANSWERS + [dont_use_changes_msg]:
self.should_overwrite_files = True
elif use_changes.lower() in AFFIRMATIVE_ANSWERS + [use_changes_msg]:
self.should_overwrite_files = False

load_step_before_coding = ('step' in self.args and
self.args['step'] is not None and
Expand Down
3 changes: 2 additions & 1 deletion pilot/helpers/agents/CodeMonkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ def implement_code_changes(
# There are no changes or there was problem talking with the LLM, we're done here
break

print('Sending code for review...', type='verbose', category='agent:code-monkey')
print('', type='verbose', category='agent:reviewer')
content, rework_feedback = self.review_change(convo, code_change_description, file_name, file_content, content)
print('', type='verbose', category='agent:code-monkey')
print('Review finished. Continuing...', type='verbose', category='agent:code-monkey')
if not rework_feedback:
# No rework needed, we're done here
break
Expand Down
17 changes: 10 additions & 7 deletions pilot/helpers/agents/Developer.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@ def __init__(self, project):
self.debugger = Debugger(self)

def start_coding(self, task_source):
print('', type='verbose', category='agent:developer')
print('Starting development...', type='verbose', category='agent:developer')
if not self.project.finished:
self.project.current_step = 'coding'
update_app_status(self.project.args['app_id'], self.project.current_step)

# DEVELOPMENT
if not self.project.skip_steps:
print(color_green_bold("🚀 Now for the actual development...\n"))
logger.info("Starting to create the actual code...")

total_tasks = len(self.project.development_plan)
Expand Down Expand Up @@ -123,7 +122,8 @@ def implement_task(self, i, task_source, development_task=None):
:param task_source: The source of the task, one of: 'app', 'feature', 'debugger', 'iteration'.
:param development_task: The task to implement.
"""
print(color_green_bold(f'Implementing task #{i + 1}: ') + color_green(f' {development_task["description"]}\n'), category='agent:developer')
print(color_green_bold(f'Implementing task #{i + 1}: ') + color_green(f' {development_task["description"]}\n'), category='pythagora')
print(f'Starting task #{i + 1} implementation...', type='verbose', category='agent:developer')
self.project.dot_pilot_gpt.chat_log_folder(i + 1)

convo_dev_task = AgentConvo(self)
Expand Down Expand Up @@ -636,7 +636,7 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr
return_cli_response=True, is_root_task=True)},
convo=iteration_convo,
is_root_task=True,
add_loop_button=iteration_count > 3,
add_loop_button=iteration_count > 2,
category='human-test')

logger.info('response: %s', response)
Expand Down Expand Up @@ -667,7 +667,7 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr

tried_alternative_solutions_to_current_issue.append(next_solution_to_try)
else:
user_feedback = self.bug_report_generator(user_feedback)
user_feedback = self.bug_report_generator(user_feedback, user_description)

print_task_progress(1, 1, development_task['description'], 'troubleshooting', 'in_progress')
iteration_convo = AgentConvo(self)
Expand Down Expand Up @@ -713,11 +713,12 @@ def continue_development(self, iteration_convo, last_branch_name, continue_descr
self.execute_task(iteration_convo, task_steps, is_root_task=True, task_source='troubleshooting')
print_task_progress(1, 1, development_task['description'], 'troubleshooting', 'done')

def bug_report_generator(self, user_feedback):
def bug_report_generator(self, user_feedback, task_review_description):
"""
Generate a bug report from the user feedback.
:param user_feedback: The user feedback.
:param task_review_description: The task review description.
:return: The bug report.
"""
bug_report_convo = AgentConvo(self)
Expand All @@ -729,6 +730,7 @@ def bug_report_generator(self, user_feedback):
"user_feedback": user_feedback,
"app_summary": self.project.project_description,
"files": self.project.get_all_coded_files(),
"task_review_description": task_review_description,
"questions_and_answers": questions_and_answers,
}, GET_BUG_REPORT_MISSING_DATA)

Expand Down Expand Up @@ -762,6 +764,7 @@ def bug_report_generator(self, user_feedback):
bug_report_summary_convo = AgentConvo(self)
user_feedback = bug_report_summary_convo.send_message('development/bug_report_summary.prompt', {
"app_summary": self.project.project_description,
"task_review_description": task_review_description,
"user_feedback": user_feedback,
"questions_and_answers": questions_and_answers,
})
Expand All @@ -773,7 +776,7 @@ def review_task(self):
Review all task changes and refactor big files.
:return: bool - True if the task changes passed review, False if not
"""
print('', type='verbose', category='agent:reviewer')
print('Starting review of all changes made in this task...', type='verbose', category='agent:reviewer')
self.review_count += 1
review_result = self.review_code_changes()
refactoring_done = self.refactor_code()
Expand Down
15 changes: 12 additions & 3 deletions pilot/prompts/development/bug_report.prompt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ Here is description of app that you are working on:

{{ files_list }}

Client wrote this feedback:
{% if task_review_description %}
User was given instructions on how to test if the app is working correctly. Here are the instructions:
```
{{ task_review_description }}
```
{% endif %}

User wrote this feedback:
```
{{ user_feedback }}
```
{% if questions_and_answers|length > 0 %}
Here are questions and answers that you already asked the client:
Here are questions and answers that you already asked the user:
```{% for row in questions_and_answers %}
Q: {{ row.question }}
A: {{ row.answer }}
Expand All @@ -23,13 +30,15 @@ If you have enough information don't ask any questions.
When thinking of questions, consider the following:
- After getting answers to your questions, you must be able to solve the problem.
- Category on which you need more information ("general", "frontend", "backend", "database", "devops", "other")
- Client is not very technical person but understands basics. It is crucial that your questions can be answered without looking into code or knowing codebase. Do not ask how something is implemented, how code works or for code snippets.
- User is not very technical person but understands basics. It is crucial that your questions can be answered without looking into code or knowing codebase. Do not ask how something is implemented, how code works or for code snippets.
- Ask questions having in mind that you have access to whole codebase related to this issue.
- Make sure to cover all categories that you need to solve the problem.
- Ask only specific information that you need to solve the problem.
- Ask clear, short and concise questions.
- Ask only crucial questions. Do not ask for information that you do not need to solve the problem.
- Ask least amount of questions to get the most information.
- Ask least amount of questions to solve the problem.
- Do not ask any questions about recent changes in code. You should be able to solve the problem without knowing recent changes in code.

Here are some examples of good questions:
"Are there any logs in browser?"
Expand Down
10 changes: 9 additions & 1 deletion pilot/prompts/development/bug_report_summary.prompt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ You are working on this app:
{{ app_summary }}
```

{% if task_review_description %}
User was given instructions on how to test if the app is working correctly. Here are the instructions:
```
{{ task_review_description }}
```
{% endif %}

User came to you with this bug report:
```
{{ user_feedback }}
Expand All @@ -17,7 +24,7 @@ A: {{ row.answer }}

Your job is now to write issue explanation that will be sent to developer, strictly following these rules:
- If there are some logs you MUST copy all logs in whole! Do not omit any logs! This is also true for code snippets or stack traces!
- Explanation must be very clear and factual, keep it as short as possible.
- Explanation must be very clear and factual, keep it as short as possible. Do not make assumptions, only state the facts.
- When writing explanation of the issue, it is good to cover all categories that you have information on. If you don't have information about one category, then don't mention it. Here are categories: "general", "frontend", "backend", "database", "devops", "other".
- Omit all information that turns out to be irrelevant for this issue (e.g. after asking additional questions it turns out that first user message is not relevant then you should ignore it)
- Write issue explanation as if you are talking directly to developer (in first person). Do not mention "user", talk as if you found the the issue.
Expand All @@ -26,3 +33,4 @@ Your job is now to write issue explanation that will be sent to developer, stric
- Do not write any new code, only if something is provided by user.
- Have in mind that developer is smart and he will understand everything as long as you provide all information that you have and that is needed to fix this issue.
- Have in mind that issue might not be related to your current development task.
- Do not use user instructions when creating issue explanation, that is only for you to understand the issue better.
5 changes: 1 addition & 4 deletions pilot/prompts/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ def ask_for_main_app_definition(project):
def ask_user(project, question: str, require_some_input=True, hint: str = None, ignore_user_input_count: bool = False):
while True:
if hint is not None:
if project.is_extension_old_version:
print(color_white_bold(hint) + '\n', type='hint')
else:
print(color_white_bold(hint) + '\n')
print(color_white_bold(hint) + '\n')
project.finish_loading()
answer = styled_text(project, question, hint=hint, ignore_user_input_count=ignore_user_input_count)

Expand Down
7 changes: 1 addition & 6 deletions pilot/utils/custom_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
from helpers.ipc import IPCClient
from const.ipc import MESSAGE_TYPE, LOCAL_IGNORE_MESSAGE_TYPES
from utils.print import remove_ansi_codes
from utils.utils import is_extension_old_version


def get_custom_print(args):
is_old_version = is_extension_old_version(args)
built_in_print = builtins.print

def print_to_external_process(*args, **kwargs):
Expand All @@ -19,13 +17,10 @@ def print_to_external_process(*args, **kwargs):
local_print(*args, **kwargs)
return

if is_old_version and not message and kwargs['type'] != MESSAGE_TYPE['loadingFinished']:
return

ipc_client_instance.send({
'type': MESSAGE_TYPE[kwargs['type']],
'category': kwargs['category'] if 'category' in kwargs else '',
'content': message if is_old_version else remove_ansi_codes(message),
'content': remove_ansi_codes(message),
})
if kwargs['type'] == MESSAGE_TYPE['user_input_request']:
return ipc_client_instance.listen()
Expand Down
2 changes: 0 additions & 2 deletions pilot/utils/questionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ def styled_text(project, question, ignore_user_input_count=False, style=None, hi

if project is not None and project.check_ipc():
response = print(question, type='user_input_request')
if project.is_extension_old_version:
print(response)
else:
used_style = style if style is not None else style_config.get_style()
question = remove_ansi_codes(question) # Colorama and questionary are not compatible and styling doesn't work
Expand Down
15 changes: 0 additions & 15 deletions pilot/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,3 @@ def remove_lines_with_string(file_content, matching_string):
lines = file_content.split('\n')
new_lines = [line for line in lines if matching_string not in line.lower()]
return '\n'.join(new_lines)


def is_extension_old_version(args):
is_old_version = True
if "extension_version" in args:
arg_version_tuple = tuple(map(int, args["extension_version"].split('.')))
compare_version_tuple = (0, 0, 47)
exception_version = (0, 0, 46)
if arg_version_tuple == exception_version:
return False

is_old_version = arg_version_tuple <= compare_version_tuple
print(is_old_version)

return is_old_version

0 comments on commit 80a73c0

Please sign in to comment.