Separate be and fe relevant files in prompt and parallelize the algorithm

This commit is contained in:
mijauexe
2025-02-07 16:10:08 +01:00
parent 98946d8e0a
commit e339183bfb
5 changed files with 60 additions and 13 deletions

View File

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

View File

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

View File

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

View File

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

View File

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