Merge pull request #611 from Pythagora-io/alternative_solutions

Alternative solutions
This commit is contained in:
LeonOstrez
2024-02-03 16:26:30 -08:00
committed by GitHub
6 changed files with 191 additions and 31 deletions

View File

@@ -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': [
{

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View 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.

View File

@@ -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 didnt 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.