Implemented the first step in deep focus initiative. Now, when the user says there is a bug during the testing step, GPT Pilot adds logs before attempting to fix the issue

This commit is contained in:
Zvonimir Sabljic
2024-07-23 17:30:31 -07:00
parent f52e321c25
commit 9bca3c5012
15 changed files with 501 additions and 74 deletions

190
core/agents/bug_hunter.py Normal file
View File

@@ -0,0 +1,190 @@
from enum import Enum
from typing import Annotated, Literal, Union
from pydantic import BaseModel, Field
from core.agents.base import BaseAgent
from core.agents.convo import AgentConvo
from core.agents.response import AgentResponse
from core.config import magic_words
from core.db.models.project_state import IterationStatus
from core.llm.parser import JSONParser
from core.log import get_logger
log = get_logger(__name__)
class StepType(str, Enum):
ADD_LOG = "add_log"
EXPLAIN_PROBLEM = "explain_problem"
GET_ADDITIONAL_FILES = "get_additional_files"
class Log(BaseModel):
filePath: str
referenceCodeSnippet: str = Field(description="Five lines of code before the line where the log needs to be added. Make sure that this contains **ONLY** the code that is currently written in the file. It must not contain the log that you want to add.")
log: str
class AddLog(BaseModel):
type: Literal[StepType.ADD_LOG] = StepType.ADD_LOG
logsToAdd: list[Log]
class ExplainProblem(BaseModel):
type: Literal[StepType.EXPLAIN_PROBLEM] = StepType.EXPLAIN_PROBLEM
problem_explanation: str
class GetAdditionalFiles(BaseModel):
type: Literal[StepType.GET_ADDITIONAL_FILES] = StepType.GET_ADDITIONAL_FILES
filePath: str
# TODO enable LLM to ask for more files
class LoggingOptions(BaseModel):
decision: Annotated[
Union[AddLog, ExplainProblem, GetAdditionalFiles],
Field(discriminator="type"),
]
class HuntConclusionType(str, Enum):
ADD_LOGS = magic_words.ADD_LOGS
PROBLEM_IDENTIFIED = magic_words.PROBLEM_IDENTIFIED
class HuntConclusionOptions(BaseModel):
conclusion: HuntConclusionType = Field(description=f"If more logs are needed to identify the problem, respond with '{magic_words.ADD_LOGS}'. If the problem is identified, respond with '{magic_words.PROBLEM_IDENTIFIED}'.")
class BugHunter(BaseAgent):
agent_type = "bug-hunter"
display_name = "Bug Hunter"
async def run(self) -> AgentResponse:
current_iteration = self.current_state.current_iteration
if "bug_reproduction_description" not in current_iteration:
await self.get_bug_reproduction_instructions()
if current_iteration["status"] == IterationStatus.HUNTING_FOR_BUG:
# TODO determine how to find a bug (eg. check in db, ask user a question, etc.)
return await self.check_logs()
elif current_iteration["status"] == IterationStatus.AWAITING_USER_TEST:
return await self.ask_user_to_test()
elif current_iteration["status"] == IterationStatus.AWAITING_BUG_REPRODUCTION:
return await self.ask_user_to_test()
async def get_bug_reproduction_instructions(self):
llm = self.get_llm()
convo = (
AgentConvo(self)
.template(
"get_bug_reproduction_instructions",
current_task=self.current_state.current_task,
user_feedback=self.current_state.current_iteration["user_feedback"],
user_feedback_qa=self.current_state.current_iteration["user_feedback_qa"],
docs=self.current_state.docs,
next_solution_to_try=None,
)
)
bug_reproduction_instructions = await llm(convo, temperature=0)
self.next_state.current_iteration["bug_reproduction_description"] = bug_reproduction_instructions
async def check_logs(self, logs_message: str = None):
llm = self.get_llm()
convo = (
AgentConvo(self)
.template(
"iteration",
current_task=self.current_state.current_task,
user_feedback=self.current_state.current_iteration["user_feedback"],
user_feedback_qa=self.current_state.current_iteration["user_feedback_qa"],
docs=self.current_state.docs,
magic_words=magic_words,
next_solution_to_try=None
)
)
for hunting_cycle in self.current_state.current_iteration["bug_hunting_cycles"]:
convo = (convo
.assistant(hunting_cycle["human_readable_instructions"])
.template(
"log_data",
backend_logs=hunting_cycle["backend_logs"],
frontend_logs=hunting_cycle["frontend_logs"],
fix_attempted=hunting_cycle["fix_attempted"]
))
human_readable_instructions = await llm(convo, temperature=0.5)
convo = (
AgentConvo(self)
.template(
"bug_found_or_add_logs",
hunt_conclusion=human_readable_instructions,
)
.require_schema(HuntConclusionOptions)
)
hunt_conclusion = await llm(convo, parser=JSONParser(HuntConclusionOptions), temperature=0)
self.next_state.current_iteration["description"] = human_readable_instructions
self.next_state.current_iteration["bug_hunting_cycles"] += [{
"human_readable_instructions": human_readable_instructions,
"fix_attempted": False
}]
if False and hunt_conclusion.conclusion == magic_words.PROBLEM_IDENTIFIED:
# if no need for logs, implement iteration same as before
self.next_state.current_iteration["status"] = IterationStatus.AWAITING_BUG_FIX
await self.send_message("The bug is found - I'm attempting to fix it.")
else:
# if logs are needed, add logging steps
self.next_state.current_iteration["status"] = IterationStatus.AWAITING_LOGGING
await self.send_message("Adding more logs to identify the bug.")
self.next_state.flag_iterations_as_modified()
return AgentResponse.done(self)
async def ask_user_to_test(self):
reproduce_bug_and_get_logs = self.current_state.current_iteration["status"] == IterationStatus.AWAITING_BUG_REPRODUCTION
await self.send_message("You can reproduce the bug like this:\n\n" + self.current_state.current_iteration["bug_reproduction_description"])
if self.current_state.current_iteration["status"] == IterationStatus.AWAITING_USER_TEST:
user_feedback = await self.ask_question(
"Is the bug you reported fixed now?",
buttons={"yes": "Yes, the issue is fixed", "no": "No"},
default="continue",
buttons_only=True,
hint="Instructions for testing:\n\n" + self.current_state.current_iteration["bug_reproduction_description"]
)
self.next_state.current_iteration["bug_hunting_cycles"][-1]["fix_attempted"] = True
if user_feedback.button == "yes":
self.next_state.complete_iteration()
else:
reproduce_bug_and_get_logs = True
if reproduce_bug_and_get_logs:
# TODO how can we get FE and BE logs automatically?
backend_logs = await self.ask_question(
"Please do exactly what you did in the last iteration, paste **BACKEND** logs here and click CONTINUE.",
buttons={"continue": "Continue"},
default="continue",
hint="Instructions for testing:\n\n" + self.current_state.current_iteration["bug_reproduction_description"]
)
frontend_logs = await self.ask_question(
"Please paste **frontend** logs here and click CONTINUE.",
buttons={"continue": "Continue"},
default="continue",
hint="Instructions for testing:\n\n" + self.current_state.current_iteration["bug_reproduction_description"]
)
# TODO select only the logs that are new (with PYTHAGORA_DEBUGGING_LOG)
self.next_state.current_iteration["bug_hunting_cycles"][-1]["backend_logs"] = backend_logs.text
self.next_state.current_iteration["bug_hunting_cycles"][-1]["frontend_logs"] = frontend_logs.text
self.next_state.current_iteration["status"] = IterationStatus.HUNTING_FOR_BUG
return AgentResponse.done(self)

View File

@@ -1,13 +1,13 @@
from enum import Enum
from typing import Annotated, Literal, Optional, Union
from typing import Optional
from uuid import uuid4
from pydantic import BaseModel, Field
from core.agents.base import BaseAgent
from core.agents.convo import AgentConvo
from core.agents.mixins import TaskSteps
from core.agents.response import AgentResponse, ResponseType
from core.db.models.project_state import TaskStatus
from core.db.models.project_state import IterationStatus, TaskStatus
from core.db.models.specification import Complexity
from core.llm.parser import JSONParser
from core.log import get_logger
@@ -16,47 +16,6 @@ from core.telemetry import telemetry
log = get_logger(__name__)
class StepType(str, Enum):
COMMAND = "command"
SAVE_FILE = "save_file"
HUMAN_INTERVENTION = "human_intervention"
class CommandOptions(BaseModel):
command: str = Field(description="Command to run")
timeout: int = Field(description="Timeout in seconds")
success_message: str = ""
class SaveFileOptions(BaseModel):
path: str
class SaveFileStep(BaseModel):
type: Literal[StepType.SAVE_FILE] = StepType.SAVE_FILE
save_file: SaveFileOptions
class CommandStep(BaseModel):
type: Literal[StepType.COMMAND] = StepType.COMMAND
command: CommandOptions
class HumanInterventionStep(BaseModel):
type: Literal[StepType.HUMAN_INTERVENTION] = StepType.HUMAN_INTERVENTION
human_intervention_description: str
Step = Annotated[
Union[SaveFileStep, CommandStep, HumanInterventionStep],
Field(discriminator="type"),
]
class TaskSteps(BaseModel):
steps: list[Step]
class RelevantFiles(BaseModel):
relevant_files: list[str] = Field(description="List of relevant files for the current task.")
@@ -109,6 +68,17 @@ class Developer(BaseAgent):
n_tasks = 1
log.debug(f"Breaking down the task review feedback {task_review_feedback}")
await self.send_message("Breaking down the task review feedback...")
elif (self.current_state.current_iteration["status"] == IterationStatus.AWAITING_BUG_FIX or
self.current_state.current_iteration["status"] == IterationStatus.AWAITING_LOGGING):
iteration = self.current_state.current_iteration
current_task["task_review_feedback"] = None
description = iteration["bug_hunting_cycles"][-1]["human_readable_instructions"]
user_feedback = iteration["user_feedback"]
source = "bug_hunt"
n_tasks = len(self.next_state.iterations)
log.debug(f"Breaking down the logging cycle {description}")
await self.send_message("Breaking down the current iteration logging cycle ...")
else:
iteration = self.current_state.current_iteration
current_task["task_review_feedback"] = None
@@ -156,8 +126,14 @@ class Developer(BaseAgent):
self.set_next_steps(response, source)
if iteration:
self.next_state.complete_iteration()
self.next_state.action = f"Troubleshooting #{len(self.current_state.iterations)}"
# fixme please :cry:
if ("status" in iteration) and (iteration["status"] == IterationStatus.AWAITING_BUG_FIX or
iteration["status"] == IterationStatus.AWAITING_LOGGING):
self.next_state.current_iteration["status"] = IterationStatus.AWAITING_BUG_REPRODUCTION if (
iteration["status"] == IterationStatus.AWAITING_LOGGING) else IterationStatus.AWAITING_USER_TEST
else:
self.next_state.complete_iteration()
self.next_state.action = f"Troubleshooting #{len(self.current_state.iterations)}"
else:
self.next_state.action = "Task review feedback"
@@ -265,7 +241,9 @@ class Developer(BaseAgent):
}
for step in response.steps
]
if len(self.next_state.unfinished_steps) > 0 and source != "review":
if (len(self.next_state.unfinished_steps) > 0 and
source != "review" and
self.next_state.current_iteration["status"] != IterationStatus.AWAITING_LOGGING):
self.next_state.steps += [
# TODO: add refactor step here once we have the refactor agent
{

View File

@@ -3,6 +3,7 @@ from uuid import uuid4
from core.agents.base import BaseAgent
from core.agents.convo import AgentConvo
from core.agents.response import AgentResponse
from core.db.models.project_state import IterationStatus
from core.log import get_logger
log = get_logger(__name__)
@@ -110,7 +111,7 @@ class ErrorHandler(BaseAgent):
"description": llm_response,
"alternative_solutions": [],
"attempts": 1,
"completed": False,
"status": IterationStatus.HUNTING_FOR_BUG,
}
]
# TODO: maybe have ProjectState.finished_steps as well? would make the debug/ran_command prompts nicer too

View File

@@ -1,8 +1,52 @@
from typing import Optional
from enum import Enum
from typing import Annotated, Literal, Optional, Union
from pydantic import BaseModel, Field
from core.agents.convo import AgentConvo
class StepType(str, Enum):
COMMAND = "command"
SAVE_FILE = "save_file"
HUMAN_INTERVENTION = "human_intervention"
class CommandOptions(BaseModel):
command: str = Field(description="Command to run")
timeout: int = Field(description="Timeout in seconds")
success_message: str = ""
class SaveFileOptions(BaseModel):
path: str
class SaveFileStep(BaseModel):
type: Literal[StepType.SAVE_FILE] = StepType.SAVE_FILE
save_file: SaveFileOptions
class CommandStep(BaseModel):
type: Literal[StepType.COMMAND] = StepType.COMMAND
command: CommandOptions
class HumanInterventionStep(BaseModel):
type: Literal[StepType.HUMAN_INTERVENTION] = StepType.HUMAN_INTERVENTION
human_intervention_description: str
Step = Annotated[
Union[SaveFileStep, CommandStep, HumanInterventionStep],
Field(discriminator="type"),
]
class TaskSteps(BaseModel):
steps: list[Step]
class IterationPromptMixin:
"""
Provides a method to find a solution to a problem based on user feedback.
@@ -16,6 +60,7 @@ class IterationPromptMixin:
*,
user_feedback_qa: Optional[list[str]] = None,
next_solution_to_try: Optional[str] = None,
bug_hunting_cycles: Optional[dict] = None,
) -> str:
"""
Generate a new solution for the problem the user reported.
@@ -23,6 +68,7 @@ class IterationPromptMixin:
:param user_feedback: User feedback about the problem.
:param user_feedback_qa: Additional q/a about the problem provided by the user (optional).
:param next_solution_to_try: Hint from ProblemSolver on which solution to try (optional).
:param bug_hunting_cycles: Data about logs that need to be added to the code (optional).
:return: The generated solution to the problem.
"""
llm = self.get_llm()
@@ -32,6 +78,7 @@ class IterationPromptMixin:
user_feedback=user_feedback,
user_feedback_qa=user_feedback_qa,
next_solution_to_try=next_solution_to_try,
bug_hunting_cycles=bug_hunting_cycles,
)
llm_solution: str = await llm(convo)
return llm_solution

View File

@@ -2,6 +2,7 @@ from typing import Optional
from core.agents.architect import Architect
from core.agents.base import BaseAgent
from core.agents.bug_hunter import BugHunter
from core.agents.code_monkey import CodeMonkey
from core.agents.code_reviewer import CodeReviewer
from core.agents.developer import Developer
@@ -18,7 +19,7 @@ from core.agents.task_reviewer import TaskReviewer
from core.agents.tech_lead import TechLead
from core.agents.tech_writer import TechnicalWriter
from core.agents.troubleshooter import Troubleshooter
from core.db.models.project_state import TaskStatus
from core.db.models.project_state import IterationStatus, TaskStatus
from core.log import get_logger
from core.telemetry import telemetry
from core.ui.base import ProjectStage
@@ -226,12 +227,25 @@ class Orchestrator(BaseAgent):
return self.create_agent_for_step(state.current_step)
if state.unfinished_iterations:
if state.current_iteration["description"]:
# Break down the next iteration into steps
if state.current_iteration["status"] == IterationStatus.HUNTING_FOR_BUG:
# Ask the Logger to check if more logs in the code are needed
return BugHunter(self.state_manager, self.ui)
elif (state.current_iteration["status"] == IterationStatus.AWAITING_LOGGING or
state.current_iteration["status"] == IterationStatus.AWAITING_BUG_FIX):
# Ask the Logger to ask user to test new logs
return Developer(self.state_manager, self.ui)
else:
# We need to iterate over the current task but there's no solution, as Pythagora
# is stuck in a loop, and ProblemSolver needs to find alternative solutions.
elif (state.current_iteration["status"] == IterationStatus.AWAITING_USER_TEST or
state.current_iteration["status"] == IterationStatus.AWAITING_BUG_REPRODUCTION):
# Ask the Logger to ask user to test new logs
return BugHunter(self.state_manager, self.ui)
elif state.current_iteration["status"] == IterationStatus.FIND_SOLUTION:
# Find solution to the iteration problem
return Troubleshooter(self.state_manager, self.ui)
# elif state.current_iteration["status"] == IterationStatus.AWAITING_BUG_FIX:
# # Break down the next iteration into steps
# return Developer(self.state_manager, self.ui)
elif state.current_iteration["status"] == IterationStatus.PROBLEM_SOLVER:
# Call Problem Solver if the user said "I'm stuck in a loop"
return ProblemSolver(self.state_manager, self.ui)
# We have just finished the task, call Troubleshooter to ask the user to review

View File

@@ -6,6 +6,7 @@ from core.agents.base import BaseAgent
from core.agents.convo import AgentConvo
from core.agents.response import AgentResponse
from core.agents.troubleshooter import IterationPromptMixin
from core.db.models.project_state import IterationStatus
from core.llm.parser import JSONParser
from core.log import get_logger
@@ -98,6 +99,7 @@ class ProblemSolver(IterationPromptMixin, BaseAgent):
self.next_state_iteration["alternative_solutions"][index]["tried"] = True
self.next_state_iteration["description"] = llm_solution
self.next_state_iteration["attempts"] = self.iteration["attempts"] + 1
self.next_state_iteration["status"] = IterationStatus.AWAITING_BUG_FIX
self.next_state.flag_iterations_as_modified()
return AgentResponse.done(self)

View File

@@ -9,7 +9,7 @@ from core.agents.mixins import IterationPromptMixin
from core.agents.response import AgentResponse
from core.config import ROUTE_FILES_AGENT_NAME
from core.db.models.file import File
from core.db.models.project_state import TaskStatus
from core.db.models.project_state import IterationStatus, TaskStatus
from core.llm.parser import JSONParser, OptionalCodeBlockParser
from core.log import get_logger
from core.telemetry import telemetry
@@ -33,7 +33,29 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
agent_type = "troubleshooter"
display_name = "Troubleshooter"
async def run(self) -> AgentResponse:
async def run(self):
if self.current_state.unfinished_iterations:
if self.current_state.current_iteration.get("status") == IterationStatus.FIND_SOLUTION:
return await self.propose_solution()
else:
raise ValueError("There is unfinished iteration but it's not in FIND_SOLUTION state.")
else:
return await self.create_iteration()
async def propose_solution(self) -> AgentResponse:
user_feedback = self.current_state.current_iteration.get("user_feedback")
user_feedback_qa = self.current_state.current_iteration.get("user_feedback_qa")
bug_hunting_cycles = self.current_state.current_iteration.get("bug_hunting_cycles")
llm_solution = await self.find_solution(user_feedback, user_feedback_qa=user_feedback_qa, bug_hunting_cycles=bug_hunting_cycles)
self.next_state.current_iteration["description"] = llm_solution
self.next_state.current_iteration["status"] = IterationStatus.AWAITING_BUG_FIX
self.next_state.flag_iterations_as_modified()
return AgentResponse.done(self)
async def create_iteration(self) -> AgentResponse:
run_command = await self.get_run_command()
user_instructions = self.current_state.current_task.get("test_instructions")
@@ -54,7 +76,7 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
# use "current_iteration" here
last_iteration = self.current_state.iterations[-1] if len(self.current_state.iterations) >= 3 else None
should_iterate, is_loop, user_feedback = await self.get_user_feedback(
should_iterate, is_loop, bug_report, change_description = await self.get_user_feedback(
run_command,
user_instructions,
last_iteration is not None,
@@ -63,6 +85,7 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
# User tested and reported no problems, we're done with the task
return await self.complete_task()
user_feedback = bug_report or change_description
user_feedback_qa = await self.generate_bug_report(run_command, user_instructions, user_feedback)
if is_loop:
@@ -71,24 +94,30 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
return self.try_next_alternative_solution(user_feedback, user_feedback_qa)
else:
# Newly detected loop, set up an empty new iteration to trigger ProblemSolver
llm_solution = ""
iteration_status = IterationStatus.AWAITING_BUG_FIX
await self.trace_loop("loop-feedback")
else:
llm_solution = await self.find_solution(user_feedback, user_feedback_qa=user_feedback_qa)
elif bug_report is not None:
iteration_status = IterationStatus.HUNTING_FOR_BUG
elif change_description is not None:
iteration_status = IterationStatus.FIND_SOLUTION
self.next_state.iterations = self.current_state.iterations + [
{
"id": uuid4().hex,
"user_feedback": user_feedback,
"user_feedback_qa": user_feedback_qa,
"description": llm_solution,
"description": change_description,
"alternative_solutions": [],
# FIXME - this is incorrect if this is a new problem; otherwise we could
# just count the iterations
"attempts": 1,
"completed": False,
"status": iteration_status,
"bug_hunting_cycles": [],
}
]
self.next_state.flag_iterations_as_modified()
if len(self.next_state.iterations) == LOOP_THRESHOLD:
await self.trace_loop("loop-start")
@@ -187,6 +216,11 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
feedback (eg. if they just clicked on "Continue" or "I'm stuck in a loop").
"""
bug_report = None
change_description = None
is_loop = False
should_iterate = True
test_message = "Can you check if the app works please?"
if user_instructions:
hint = " Here is a description of what should be working:\n\n" + user_instructions
@@ -194,15 +228,19 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
if run_command:
await self.ui.send_run_command(run_command)
buttons = {"continue": "continue"}
buttons = {
"continue": "Everything works",
"change": "I want to make a change",
"bug": "There is an issue"
}
if last_iteration:
buttons["loop"] = "I'm stuck in a loop"
user_response = await self.ask_question(test_message, buttons=buttons, default="continue", hint=hint)
user_response = await self.ask_question(test_message, buttons=buttons, default="continue", buttons_only=True, hint=hint)
if user_response.button == "continue" or user_response.cancelled:
return False, False, ""
should_iterate = False
if user_response.button == "loop":
elif user_response.button == "loop":
await telemetry.trace_code_event(
"stuck-in-loop",
{
@@ -218,16 +256,23 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
},
},
)
return True, True, ""
is_loop = True
return True, False, user_response.text
elif user_response.button == "change":
user_description = await self.ask_question("Please describe the change you want to make (one at the time please)")
change_description = user_description.text
elif user_response.button == "bug":
user_description = await self.ask_question("Please describe the issue you found (one at the time please)")
bug_report = user_description.text
return should_iterate, is_loop, bug_report, change_description
def try_next_alternative_solution(self, user_feedback: str, user_feedback_qa: list[str]) -> AgentResponse:
"""
Call the ProblemSolver to try an alternative solution.
Stores the user feedback and sets iteration state (not completed, no description)
so that ProblemSolver will be triggered.
Stores the user feedback and sets iteration state so that ProblemSolver will be triggered.
:param user_feedback: User feedback to store in the iteration state.
:param user_feedback_qa: Additional questions/answers about the problem.
@@ -238,7 +283,7 @@ class Troubleshooter(IterationPromptMixin, BaseAgent):
next_state_iteration["user_feedback"] = user_feedback
next_state_iteration["user_feedback_qa"] = user_feedback_qa
next_state_iteration["attempts"] += 1
next_state_iteration["completed"] = False
next_state_iteration["status"] = IterationStatus.PROBLEM_SOLVER
self.next_state.flag_iterations_as_modified()
self.next_state.action = f"Alternative solution (attempt #{next_state_iteration['attempts']})"
return AgentResponse.done(self)

View File

@@ -0,0 +1,2 @@
PROBLEM_IDENTIFIED = "PROBLEM_IDENTIFIED"
ADD_LOGS = "ADD_LOGS"

View File

@@ -30,6 +30,19 @@ class TaskStatus:
SKIPPED = "skipped"
class IterationStatus:
"""Status of an iteration."""
HUNTING_FOR_BUG = "check_logs"
AWAITING_LOGGING = "awaiting_logging"
AWAITING_USER_TEST = "awaiting_user_test"
AWAITING_BUG_FIX = "awaiting_bug_fix"
AWAITING_BUG_REPRODUCTION = "awaiting_bug_reproduction"
FIND_SOLUTION = "find_solution"
PROBLEM_SOLVER = "problem_solver"
DONE = "done"
class ProjectState(Base):
__tablename__ = "project_states"
__table_args__ = (
@@ -105,7 +118,7 @@ class ProjectState(Base):
:return: List of unfinished iterations.
"""
return [iteration for iteration in self.iterations if not iteration.get("completed")]
return [iteration for iteration in self.iterations if iteration.get("status") != IterationStatus.DONE]
@property
def current_iteration(self) -> Optional[dict]:
@@ -285,7 +298,7 @@ class ProjectState(Base):
raise ValueError("Current state is read-only (already has a next state).")
log.debug(f"Completing iteration {self.unfinished_iterations[0]}")
self.unfinished_iterations[0]["completed"] = True
self.unfinished_iterations[0]["status"] = IterationStatus.DONE
self.flag_iterations_as_modified()
def flag_iterations_as_modified(self):

View File

@@ -0,0 +1,6 @@
We are working on a solving a technical problem in a codebase and here is a conclusion from a team member:
--- TEAM_MEMBER_CONCLUSION ---
{{ hunt_conclusion }}
--- END_OF_TEAM_MEMBER_CONCLUSION ---
Please tell me if the conclusion from the team member is to add more logs around the code or if the conclusion is that there are all information needed to fix the issue.

View File

@@ -0,0 +1,31 @@
You are working on an app called "{{ state.branch.project.name }}" and you need to write code for the entire application.
{% include "partials/project_details.prompt" %}
{% if state.tasks and state.current_task %}
Development process of this app was split into smaller tasks. Here is the list of all tasks:
```{% for task in state.tasks %}
{{ loop.index }}. {{ task.description }}
{% endfor %}
```
You are currently working on, and have to focus only on, this task:
```
{{ current_task.description }}
```
{% endif %}
A part of the app is already finished.
{% include "partials/files_list.prompt" %}
{% include "partials/user_feedback.prompt" %}
{% if next_solution_to_try is not none %}
Focus on solving this issue in the following way:
```
{{ next_solution_to_try }}
```
{% endif %}
{#{% include "partials/doc_snippets.prompt" %}#}
Based on this information, you need to tell me in 2-3 sentences how can I reproduce the issue that the user experienced.

View File

@@ -0,0 +1,43 @@
You are working on an app called "{{ state.branch.project.name }}" and you need to write code for the entire application.
{% include "partials/project_details.prompt" %}
{% if state.tasks and state.current_task %}
Development process of this app was split into smaller tasks. Here is the list of all tasks:
```{% for task in state.tasks %}
{{ loop.index }}. {{ task.description }}
{% endfor %}
```
You are currently working on, and have to focus only on, this task:
```
{{ current_task.description }}
```
{% endif %}
A part of the app is already finished.
{% include "partials/files_list.prompt" %}
{% include "partials/user_feedback.prompt" %}
{% if next_solution_to_try is not none %}
Focus on solving this issue in the following way:
```
{{ next_solution_to_try }}
```
{% endif %}
{#{% include "partials/doc_snippets.prompt" %}#}
Based on this information, you need to figure out where is the problem that the user described. You have 2 options - to tell me exactly where is the problem happening or to add more logs to better determine where is the problem. If you think we should add more logs around the code to better understand the problem, tell me code snippets in which we should add the logs. If you think you know where the issue is, don't add any new logs but explain what log print tell point you to the problem, what the problem is, what is the solution to this problem and how the solution will fix the problem. What is your answer?
{#**IMPORTANT**
I you decide to add logs, start the message with "{{ magic_words.ADD_LOGS }}". Make sure that the log starts with "PYTHAGORA_DEBUGGING_LOG". For example, if you want to add a log in a Python code `print("Hello, World!")`, you should put `print("PYTHAGORA_DEBUGGING_LOG: Hello, World!")` instead. This refers to **ONLY** the logs you want to add that are not in the codebase at the moment. All logs that are in the codebase already, you must not change. When you write code, you **MUST NOT** add any new lines of code except the logs.
Your message will be read by a developer so you don't have to write the entire files in which you want to add logs to. Just write the lines of code where you want to add logs so that the developer reading your message understands where should they put the logs to.
**IMPORTANT**
If you have all the information you need to solve the problem, do not add any logs but explain what is the problem, where in the code is it and how should it be fixed and end the response with with "{{ magic_words.PROBLEM_IDENTIFIED }}". Remember, if you mentioned to add any logs, you **MUST NOT** say "{{ magic_words.PROBLEM_IDENTIFIED }}".
{% include "partials/file_naming.prompt" %}
{% include "partials/relative_paths.prompt" %}
#}

View File

@@ -0,0 +1,12 @@
{% if backend_logs is not none %}Here are the logs we added to the backend:
```
{{ backend_logs }}
```
{% endif %}{% if frontend_logs is not none %}
Here are the logs we added to the frontend:
```
{{ frontend_logs }}
```
{% endif %}{% if fix_attempted %}
The problem wasn't solved with the last changes. You have 2 options - to tell me exactly where is the problem happening or to add more logs to better determine where is the problem. If you think we should add more logs around the code to better understand the problem, tell me code snippets in which we should add the logs. If you think you know where the issue is, don't add any new logs but explain what log print tell point you to the problem, what the problem is, what is the solution to this problem and how the solution will fix the problem. What is your answer?
{% endif %}

View File

@@ -0,0 +1,43 @@
Ok, now, take your response and convert it to a list of actionable steps that will be executed by a machine.
Analyze the entire message, think step by step and make sure that you don't omit any information
when converting this message to steps.
Each step can be either:
* `command` - command to run (must be able to run on a {{ os }} machine, assume current working directory is project root folder)
* `save_file` - create or update ONE file (only provide file path, not contents)
* `human_intervention` - if you need the human to do something, use this type of step and explain in details what you want the human to do. NEVER use `human_intervention` for testing, as testing will be done separately by a dedicated QA after all the steps are done. Also you MUST NOT use `human_intervention` to ask the human to write or review code.
**IMPORTANT**: If multiple changes are required for same file, you must provide single `save_file` step for each file.
{% include "partials/file_naming.prompt" %}
{% include "partials/relative_paths.prompt" %}
{% include "partials/execution_order.prompt" %}
{% include "partials/human_intervention_explanation.prompt" %}
**IMPORTANT**: Remember, NEVER output human intervention steps to do manual tests or coding tasks, even if the previous message asks for it! The testing will be done *after* these steps and you MUST NOT include testing in these steps.
Examples:
------------------------example_1---------------------------
```
{
"tasks": [
{
"type": "save_file",
"save_file": {
"path": "server.js"
},
},
{
"type": "command",
"command": {
"command": "mv index.js public/index.js"",
"timeout": 5,
"success_message": "",
"command_id": "move_index_file"
}
}
]
}
```
------------------------end_of_example_1---------------------------

View File