mirror of
https://github.com/Pythagora-io/gpt-pilot.git
synced 2026-01-10 13:37:55 -05:00
Separate be and fe relevant files in prompt and parallelize the algorithm
This commit is contained in:
@@ -134,7 +134,7 @@ class Developer(ChatWithBreakdownMixin, RelevantFilesMixin, BaseAgent):
|
||||
log.debug(f"Breaking down the iteration {description}")
|
||||
|
||||
if self.current_state.files and self.current_state.relevant_files is None:
|
||||
await self.get_relevant_files(user_feedback, description)
|
||||
await self.get_relevant_files_parallel(user_feedback, description)
|
||||
|
||||
await self.ui.send_task_progress(
|
||||
n_tasks, # iterations and reviews can be created only one at a time, so we are always on last one
|
||||
@@ -210,7 +210,7 @@ class Developer(ChatWithBreakdownMixin, RelevantFilesMixin, BaseAgent):
|
||||
|
||||
log.debug(f"Current state files: {len(self.current_state.files)}, relevant {self.current_state.relevant_files}")
|
||||
# Check which files are relevant to the current task
|
||||
await self.get_relevant_files()
|
||||
await self.get_relevant_files_parallel()
|
||||
|
||||
current_task_index = self.current_state.tasks.index(current_task)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import json
|
||||
from difflib import unified_diff
|
||||
from typing import List, Optional, Union
|
||||
@@ -134,13 +135,44 @@ class IterationPromptMixin:
|
||||
|
||||
class RelevantFilesMixin:
|
||||
"""
|
||||
Provides a method to get relevant files for the current task.
|
||||
Asynchronously retrieves relevant files for the current task by separating front-end and back-end files, and processing them in parallel.
|
||||
|
||||
This method initiates two asynchronous tasks to fetch relevant files for the front-end (client) and back-end (server) respectively.
|
||||
It then combines the results, filters out any non-existing files, and updates the current and next state with the relevant files.
|
||||
"""
|
||||
|
||||
async def get_relevant_files(
|
||||
async def get_relevant_files_parallel(
|
||||
self, user_feedback: Optional[str] = None, solution_description: Optional[str] = None
|
||||
) -> AgentResponse:
|
||||
log.debug("Getting relevant files for the current task")
|
||||
tasks = [
|
||||
self.get_relevant_files(
|
||||
user_feedback=user_feedback, solution_description=solution_description, dir_type="client"
|
||||
),
|
||||
self.get_relevant_files(
|
||||
user_feedback=user_feedback, solution_description=solution_description, dir_type="server"
|
||||
),
|
||||
]
|
||||
|
||||
responses = await asyncio.gather(*tasks)
|
||||
|
||||
relevant_files = [item for sublist in responses for item in sublist]
|
||||
|
||||
existing_files = {file.path for file in self.current_state.files}
|
||||
relevant_files = [path for path in relevant_files if path in existing_files]
|
||||
self.current_state.relevant_files = relevant_files
|
||||
self.next_state.relevant_files = relevant_files
|
||||
|
||||
return AgentResponse.done(self)
|
||||
|
||||
async def get_relevant_files(
|
||||
self,
|
||||
user_feedback: Optional[str] = None,
|
||||
solution_description: Optional[str] = None,
|
||||
dir_type: Optional[str] = None,
|
||||
) -> list[str]:
|
||||
log.debug(
|
||||
"Getting relevant files for the current task for: " + ("frontend" if dir_type == "client" else "backend")
|
||||
)
|
||||
done = False
|
||||
relevant_files = set()
|
||||
llm = self.get_llm(GET_RELEVANT_FILES_AGENT_NAME)
|
||||
@@ -151,6 +183,7 @@ class RelevantFilesMixin:
|
||||
user_feedback=user_feedback,
|
||||
solution_description=solution_description,
|
||||
relevant_files=relevant_files,
|
||||
dir_type=dir_type,
|
||||
)
|
||||
.require_schema(RelevantFiles)
|
||||
)
|
||||
@@ -184,11 +217,7 @@ class RelevantFilesMixin:
|
||||
done = getattr(action, "done", False)
|
||||
|
||||
existing_files = {file.path for file in self.current_state.files}
|
||||
relevant_files = [path for path in relevant_files if path in existing_files]
|
||||
self.current_state.relevant_files = relevant_files
|
||||
self.next_state.relevant_files = relevant_files
|
||||
|
||||
return AgentResponse.done(self)
|
||||
return [path for path in relevant_files if path in existing_files]
|
||||
|
||||
|
||||
class FileDiffMixin:
|
||||
|
||||
@@ -178,7 +178,7 @@ class TechLead(RelevantFilesMixin, BaseAgent):
|
||||
await self.send_message("Creating the development plan ...")
|
||||
|
||||
if epic.get("source") == "feature":
|
||||
await self.get_relevant_files(user_feedback=epic.get("description"))
|
||||
await self.get_relevant_files_parallel(user_feedback=epic.get("description"))
|
||||
|
||||
llm = self.get_llm(TECH_LEAD_PLANNING)
|
||||
convo = (
|
||||
|
||||
@@ -297,7 +297,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
|
||||
if user_description.button == "back":
|
||||
continue
|
||||
change_description = user_description.text
|
||||
await self.get_relevant_files(user_feedback=change_description)
|
||||
await self.get_relevant_files_parallel(user_feedback=change_description)
|
||||
break
|
||||
|
||||
elif user_response.button == "bug":
|
||||
@@ -310,7 +310,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
|
||||
if user_description.button == "back":
|
||||
continue
|
||||
bug_report = user_description.text
|
||||
await self.get_relevant_files(user_feedback=bug_report)
|
||||
await self.get_relevant_files_parallel(user_feedback=bug_report)
|
||||
break
|
||||
|
||||
return should_iterate, is_loop, bug_report, change_description
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
{% if dir_type is defined %}
|
||||
{% if dir_type == "client" %}
|
||||
Now you need to focus only on the frontend files. These files are currently implemented on the frontend that contain all API requests to the backend with structure that you need to follow:
|
||||
{% for file in state.files %}{% if 'client/' in file.path %}
|
||||
* `{{ file.path }}{% if file.meta.get("description") %}: {{file.meta.description}}{% endif %}`
|
||||
{% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if dir_type == "server" %}
|
||||
Now you need to focus only on the backend files. These files are currently implemented in the project on the backend:
|
||||
{% for file in state.files %}{% if 'server/' in file.path %}
|
||||
* `{{ file.path }}{% if file.meta.get("description") %}: {{file.meta.description}}{% endif %}`
|
||||
{% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
These files are currently implemented on the frontend that contain all API requests to the backend with structure that you need to follow:
|
||||
{% for file in state.files %}
|
||||
{% if not state.has_frontend() or (state.has_frontend() and state.epics|length > 1 and 'client/src/components/ui' not in file.path ) or (state.has_frontend() and state.epics|length == 1 ) %}
|
||||
@@ -7,3 +23,5 @@ These files are currently implemented in the project on the backend:
|
||||
{% for file in state.files %}{% if 'server/' in file.path %}
|
||||
* `{{ file.path }}{% if file.meta.get("description") %}: {{file.meta.description}}{% endif %}`
|
||||
{% endif %}{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user