mirror of
https://github.com/Pythagora-io/gpt-pilot.git
synced 2026-01-10 13:37:55 -05:00
Merge pull request #611 from Pythagora-io/alternative_solutions
Alternative solutions
This commit is contained in:
@@ -452,6 +452,33 @@ DEV_STEPS = {
|
||||
},
|
||||
}
|
||||
|
||||
ALTERNATIVE_SOLUTIONS = {
|
||||
'definitions': [
|
||||
{
|
||||
'name': 'get_alternative_solutions_to_issue',
|
||||
'description': 'Gets alternative solutions to the recurring issue that was labeled as loop by the user.',
|
||||
'parameters': {
|
||||
'type': 'object',
|
||||
"properties": {
|
||||
"description_of_tried_solutions": {
|
||||
'type': 'string',
|
||||
'description': 'A description of the solutions that were tried to solve the recurring issue that was labeled as loop by the user.',
|
||||
},
|
||||
"alternative_solutions": {
|
||||
'type': 'array',
|
||||
'description': 'List of all alternative solutions to the recurring issue that was labeled as loop by the user.',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'description': 'Development step that needs to be done to complete the entire task.',
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ['description_of_tried_solutions', 'alternative_solutions'],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
CODE_CHANGES = {
|
||||
'definitions': [
|
||||
{
|
||||
|
||||
@@ -2,4 +2,6 @@ CHECK_AND_CONTINUE = 'Is everything working? Let me know if something needs to b
|
||||
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']
|
||||
STUCK_IN_LOOP = 'I\'m stuck in loop'
|
||||
NONE_OF_THESE = 'none of these'
|
||||
MAX_PROJECT_NAME_LENGTH = 50
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Tuple
|
||||
|
||||
import peewee
|
||||
|
||||
from const.messages import CHECK_AND_CONTINUE, AFFIRMATIVE_ANSWERS, NEGATIVE_ANSWERS
|
||||
from const.messages import CHECK_AND_CONTINUE, AFFIRMATIVE_ANSWERS, NEGATIVE_ANSWERS, STUCK_IN_LOOP
|
||||
from utils.style import color_yellow_bold, color_cyan, color_white_bold, color_red_bold
|
||||
from const.common import STEPS
|
||||
from database.database import delete_unconnected_steps_from, delete_all_app_development_data, \
|
||||
@@ -505,7 +505,7 @@ class Project:
|
||||
delete_unconnected_steps_from(self.checkpoints['last_command_run'], 'previous_step')
|
||||
delete_unconnected_steps_from(self.checkpoints['last_user_input'], 'previous_step')
|
||||
|
||||
def ask_for_human_intervention(self, message, description=None, cbs={}, convo=None, is_root_task=False):
|
||||
def ask_for_human_intervention(self, message, description=None, cbs={}, convo=None, is_root_task=False, add_loop_button=False):
|
||||
answer = ''
|
||||
question = color_yellow_bold(message)
|
||||
|
||||
@@ -515,7 +515,7 @@ class Project:
|
||||
reset_branch_id = None if convo is None else convo.save_branch()
|
||||
|
||||
while answer.lower() != 'continue':
|
||||
print('continue', type='button')
|
||||
print('continue' + (f'/{STUCK_IN_LOOP}' if add_loop_button else ''), type='button')
|
||||
answer = ask_user(self, CHECK_AND_CONTINUE,
|
||||
require_some_input=False,
|
||||
hint=question)
|
||||
|
||||
@@ -3,7 +3,7 @@ import uuid
|
||||
import re
|
||||
import json
|
||||
|
||||
from const.messages import WHEN_USER_DONE, AFFIRMATIVE_ANSWERS, NEGATIVE_ANSWERS
|
||||
from const.messages import WHEN_USER_DONE, AFFIRMATIVE_ANSWERS, NEGATIVE_ANSWERS, STUCK_IN_LOOP, NONE_OF_THESE
|
||||
from utils.style import (
|
||||
color_green,
|
||||
color_green_bold,
|
||||
@@ -25,7 +25,7 @@ from helpers.Agent import Agent
|
||||
from helpers.AgentConvo import AgentConvo
|
||||
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 EXECUTE_COMMANDS, GET_TEST_TYPE, IMPLEMENT_TASK, COMMAND_TO_RUN
|
||||
from const.function_calls import EXECUTE_COMMANDS, GET_TEST_TYPE, IMPLEMENT_TASK, COMMAND_TO_RUN, ALTERNATIVE_SOLUTIONS
|
||||
from database.database import save_progress, get_progress_steps, update_app_status
|
||||
from utils.telemetry import telemetry
|
||||
from prompts.prompts import ask_user
|
||||
@@ -553,7 +553,13 @@ class Developer(Agent):
|
||||
return self.task_postprocessing(convo, development_task, continue_development, result, function_uuid)
|
||||
|
||||
def continue_development(self, iteration_convo, last_branch_name, continue_description='', development_task=None):
|
||||
llm_solutions = self.project.last_iteration['prompt_data']['previous_solutions'] if (self.project.last_iteration and 'previous_solutions' in self.project.last_iteration['prompt_data']) else []
|
||||
alternative_solutions_to_current_issue = self.project.last_iteration['prompt_data']['alternative_solutions_to_current_issue'] if (self.project.last_iteration and 'alternative_solutions_to_current_issue' in self.project.last_iteration['prompt_data']) else []
|
||||
tried_alternative_solutions_to_current_issue = self.project.last_iteration['prompt_data']['tried_alternative_solutions_to_current_issue'] if (self.project.last_iteration and 'tried_alternative_solutions_to_current_issue' in self.project.last_iteration['prompt_data']) else []
|
||||
next_solution_to_try = None
|
||||
iteration_count = self.project.last_iteration['prompt_data']['iteration_count'] if (self.project.last_iteration and 'iteration_count' in self.project.last_iteration['prompt_data']) else 0
|
||||
while True:
|
||||
iteration_count += 1
|
||||
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)
|
||||
@@ -583,7 +589,8 @@ class Developer(Agent):
|
||||
force=True,
|
||||
return_cli_response=True, is_root_task=True)},
|
||||
convo=iteration_convo,
|
||||
is_root_task=True)
|
||||
is_root_task=True,
|
||||
add_loop_button=iteration_count > 3)
|
||||
|
||||
logger.info('response: %s', response)
|
||||
user_feedback = response['user_input'] if 'user_input' in response else None
|
||||
@@ -592,6 +599,24 @@ class Developer(Agent):
|
||||
return {"success": True, "user_input": user_feedback}
|
||||
|
||||
if user_feedback is not None:
|
||||
stuck_in_loop = user_feedback.startswith(STUCK_IN_LOOP)
|
||||
if stuck_in_loop:
|
||||
# Remove the STUCK_IN_LOOP prefix from the user feedback
|
||||
user_feedback = user_feedback[len(STUCK_IN_LOOP):]
|
||||
stuck_in_loop = False
|
||||
if len(alternative_solutions_to_current_issue) > 0:
|
||||
next_solution_to_try_index = self.ask_user_for_next_solution(alternative_solutions_to_current_issue)
|
||||
if next_solution_to_try_index == NONE_OF_THESE:
|
||||
next_solution_to_try = self.get_alternative_solutions(development_task, user_feedback, llm_solutions, tried_alternative_solutions_to_current_issue + alternative_solutions_to_current_issue)
|
||||
else:
|
||||
next_solution_to_try = alternative_solutions_to_current_issue.pop(next_solution_to_try_index - 1)
|
||||
else:
|
||||
description_of_tried_solutions, alternative_solutions_to_current_issue, next_solution_to_try = self.get_alternative_solutions(development_task, user_feedback, llm_solutions, tried_alternative_solutions_to_current_issue)
|
||||
if len(tried_alternative_solutions_to_current_issue) == 0:
|
||||
tried_alternative_solutions_to_current_issue.append(description_of_tried_solutions)
|
||||
|
||||
tried_alternative_solutions_to_current_issue.append(next_solution_to_try)
|
||||
|
||||
iteration_convo = AgentConvo(self)
|
||||
iteration_description = iteration_convo.send_message('development/iteration.prompt', {
|
||||
"name": self.project.args['name'],
|
||||
@@ -608,6 +633,16 @@ class Developer(Agent):
|
||||
"development_tasks": self.project.development_plan,
|
||||
"files": self.project.get_all_coded_files(),
|
||||
"user_input": user_feedback,
|
||||
"previous_solutions": llm_solutions[-3:],
|
||||
"next_solution_to_try": next_solution_to_try,
|
||||
"alternative_solutions_to_current_issue": alternative_solutions_to_current_issue,
|
||||
"tried_alternative_solutions_to_current_issue": tried_alternative_solutions_to_current_issue,
|
||||
"iteration_count": iteration_count
|
||||
})
|
||||
|
||||
llm_solutions.append({
|
||||
"user_feedback": user_feedback,
|
||||
"llm_proposal": iteration_description
|
||||
})
|
||||
|
||||
instructions_prefix = " ".join(iteration_description.split()[:5])
|
||||
@@ -743,3 +778,47 @@ class Developer(Agent):
|
||||
# code_changes_details = get_step_code_changes()
|
||||
# # TODO: give to code monkey for implementation
|
||||
pass
|
||||
|
||||
def get_alternative_solutions(self, development_task, user_feedback, previous_solutions, tried_alternative_solutions_to_current_issue):
|
||||
convo = AgentConvo(self)
|
||||
response = convo.send_message('development/get_alternative_solutions.prompt', {
|
||||
"name": self.project.args['name'],
|
||||
"app_type": self.project.args['app_type'],
|
||||
"app_summary": self.project.project_description,
|
||||
"architecture": self.project.architecture,
|
||||
"technologies": self.project.system_dependencies + self.project.package_dependencies,
|
||||
"directory_tree": self.project.get_directory_tree(True),
|
||||
"current_task": development_task,
|
||||
"development_tasks": self.project.development_plan,
|
||||
"files": self.project.get_all_coded_files(),
|
||||
"user_input": user_feedback,
|
||||
"previous_solutions": previous_solutions,
|
||||
"tried_alternative_solutions_to_current_issue": tried_alternative_solutions_to_current_issue,
|
||||
}, ALTERNATIVE_SOLUTIONS)
|
||||
|
||||
next_solution_to_try_index = self.ask_user_for_next_solution(response['alternative_solutions'])
|
||||
if isinstance(next_solution_to_try_index, str) and next_solution_to_try_index == NONE_OF_THESE:
|
||||
return self.get_alternative_solutions(development_task, user_feedback, previous_solutions, tried_alternative_solutions_to_current_issue + response['alternative_solutions'])
|
||||
|
||||
next_solution_to_try = response['alternative_solutions'].pop(next_solution_to_try_index - 1)
|
||||
|
||||
return response['description_of_tried_solutions'], response['alternative_solutions'], next_solution_to_try
|
||||
|
||||
def ask_user_for_next_solution(self, alternative_solutions):
|
||||
solutions_indices_as_strings = [str(i + 1) for i in range(len(alternative_solutions))]
|
||||
string_for_buttons = '/'.join(solutions_indices_as_strings) + '/' + (NONE_OF_THESE[0].upper() + NONE_OF_THESE[1:])
|
||||
|
||||
description_of_solutions = '\n\n'.join([f"{index + 1}: {sol}" for index, sol in enumerate(alternative_solutions)])
|
||||
print(string_for_buttons, type='button')
|
||||
next_solution_to_try_index = ask_user(self.project, 'Choose which solution would you like GPT Pilot to try next?',
|
||||
require_some_input=False,
|
||||
hint=description_of_solutions)
|
||||
|
||||
if next_solution_to_try_index in solutions_indices_as_strings:
|
||||
next_solution_to_try_index = int(next_solution_to_try_index)
|
||||
elif next_solution_to_try_index.lower() == NONE_OF_THESE:
|
||||
next_solution_to_try_index = NONE_OF_THESE
|
||||
else:
|
||||
next_solution_to_try_index = 1
|
||||
|
||||
return next_solution_to_try_index
|
||||
|
||||
70
pilot/prompts/development/get_alternative_solutions.prompt
Normal file
70
pilot/prompts/development/get_alternative_solutions.prompt
Normal file
@@ -0,0 +1,70 @@
|
||||
You are working on a {{ app_type }} called "{{ name }}" and you need to write code for the entire application.
|
||||
|
||||
Here is a high level description of "{{ name }}":
|
||||
```
|
||||
{{ app_summary }}
|
||||
```
|
||||
|
||||
Project architecture:
|
||||
{{ architecture }}
|
||||
|
||||
Here are the technologies that you need to use for this project:
|
||||
{% for tech in technologies %}
|
||||
* {{ tech["name"] }} - {{ tech["description"] }}{% endfor %}
|
||||
|
||||
{% if development_tasks and current_task %}
|
||||
Development process of this app was split into smaller tasks. Here is the list of all tasks:
|
||||
```{% for task in development_tasks %}
|
||||
{{ loop.index }}. {{ task['description'] }}
|
||||
{% endfor %}
|
||||
```
|
||||
You are currently working on task "{{ current_task.description }}" and you have to focus only on that task.
|
||||
|
||||
{% endif %}
|
||||
A part of the app is already finished.
|
||||
{{ files_list }}
|
||||
|
||||
You are trying to solve an issue that your colleague is reporting. You tried {{ previous_solutions|length }} times to solve it but it was unsuccessful.
|
||||
{% if tried_alternative_solutions_to_current_issue|length > 0 %}
|
||||
|
||||
Here are the alternative solutions that you tried to solve the issue:
|
||||
{% for solution in tried_alternative_solutions_to_current_issue %}
|
||||
----------------------------start_of_solution_{{ loop.index }}----------------------------
|
||||
{{ solution }}
|
||||
----------------------------end_of_solution_{{ loop.index }}----------------------------
|
||||
{% endfor %}
|
||||
{% elif previous_solutions|length > 0 %}
|
||||
First time, your colleague gave you this report:
|
||||
{% for solution in previous_solutions %}
|
||||
----------------------------start_of_report_{{ loop.index }}----------------------------
|
||||
{{ solution['user_feedback'] }}
|
||||
----------------------------end_of_report_{{ loop.index }}----------------------------
|
||||
|
||||
Then, you gave the following proposal (proposal_{{ loop.index }}) of what needs to be done to fix the issue:
|
||||
----------------------------start_of_proposal_{{ loop.index }}----------------------------
|
||||
{{ solution['llm_proposal'] }}
|
||||
----------------------------end_of_of_proposal_{{ loop.index }}----------------------------
|
||||
|
||||
{% if loop.index < previous_solutions|length %}
|
||||
Then, upon implementing these changes, your colleague came back with the following report:
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if user_input != '' %}
|
||||
After implementing these changes as well, your colleague who is testing the app "{{ name }}" sent you this report now:
|
||||
```
|
||||
{{ user_input }}
|
||||
```
|
||||
|
||||
You tried to solve this problem before but your colleague is telling you that you got into a loop where all your tries end up the same way - with an error.
|
||||
{%- endif -%}
|
||||
|
||||
It seems that the solutions you're proposing aren't working.
|
||||
|
||||
Now, think about 5 alternative solutions to get this code to work that are most probable to solve this issue.
|
||||
|
||||
Every proposed solution needs to be concrete and not vague (eg, it cannot be "Review and change apps functionality") and based on the code changes. A solution can be complex if it's related to the same part of the code (eg. "Try changing the input variables X, Y and Z to a method N").
|
||||
|
||||
Order them in the order of the biggest probability of fixing the problem. A developer will then go through this list item by item, try to implement it, and check if it solved the issue until the end of the list.
|
||||
Let's think step by step.
|
||||
@@ -24,38 +24,20 @@ You are currently working on task "{{ current_task.description }}" and you have
|
||||
A part of the app is already finished.
|
||||
{{ files_list }}
|
||||
|
||||
{#% if previous_solutions|length == 0 %#}
|
||||
|
||||
{% if user_input != '' %}
|
||||
Now, your colleague who is testing the app "{{ name }}" sent you some additional info. Here it is:
|
||||
```
|
||||
{{ user_input }}
|
||||
```
|
||||
{#% elif %}
|
||||
You are trying to solve an issue that your colleague is reporting. You tried {{ previous_solutions|length }} times to solve it but it was unsuccessful.
|
||||
First time, your colleague gave you this report:
|
||||
{% for solution in previous_solutions %}
|
||||
----------------------------start_of_report_{{ loop.index + 1 }}----------------------------
|
||||
solution['report']
|
||||
----------------------------end_of_report_{{ loop.index + 1 }}----------------------------
|
||||
|
||||
Then, you gave the following proposal (proposal_{{ loop.index + 1 }}) of what needs to be done to fix the issue:
|
||||
----------------------------start_of_proposal_{{ loop.index + 1 }}----------------------------
|
||||
solution['proposal']
|
||||
----------------------------end_of_of_proposal_{{ loop.index + 1 }}----------------------------
|
||||
|
||||
{% if loop.index < previous_solutions|length %}
|
||||
Then, upon implementing these changes, your colleague came back with the following report:
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
After implementing these changes as well, your colleague who is testing the app "{{ name }}" sent you this report now:
|
||||
{% if next_solution_to_try is not none %}
|
||||
Focus on solving this issue in the following way:
|
||||
```
|
||||
{{ user_input }}
|
||||
{{ next_solution_to_try }}
|
||||
```
|
||||
|
||||
Every time your proposals didn’t lead to the solution. This needs to be fixed and you need to try an alternative solution to this problem. Think step by step any see what are other ways how you this issue can be fixed, propose all changes that are needed to solve this issue and do not repeat previous mistakes.
|
||||
{% endif -%#}
|
||||
|
||||
Can you debug this issue or implement changes to comply with the additional input?
|
||||
{% endif %}
|
||||
Can you debug this issue or implement changes to comply with the additional user input?
|
||||
|
||||
Tell me all the new code that needs to be written or modified to implement current task and have it fully working. You can count that the environment is set up previously and packages listed in files are installed so tell me only commands needed for installation of new dependencies, if there are any.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user