mirror of
https://github.com/Pythagora-io/gpt-pilot.git
synced 2026-01-10 13:37:55 -05:00
Fix most of the history print errors
This commit is contained in:
@@ -10,6 +10,9 @@ from core.agents.mixins import ChatWithBreakdownMixin, TestSteps
|
||||
from core.agents.response import AgentResponse
|
||||
from core.config import CHECK_LOGS_AGENT_NAME, magic_words
|
||||
from core.config.actions import (
|
||||
BH_ADDITIONAL_FEEDBACK,
|
||||
BH_HUMAN_TEST_AGAIN,
|
||||
BH_IS_BUG_FIXED,
|
||||
BH_START_BUG_HUNT,
|
||||
BH_START_USER_TEST,
|
||||
BH_STARTING_PAIR_PROGRAMMING,
|
||||
@@ -162,7 +165,7 @@ class BugHunter(ChatWithBreakdownMixin, BaseAgent):
|
||||
await self.ui.send_run_command(self.current_state.run_command)
|
||||
|
||||
await self.ask_question(
|
||||
"Please test the app again.",
|
||||
BH_HUMAN_TEST_AGAIN,
|
||||
buttons={"done": "I am done testing"},
|
||||
buttons_only=True,
|
||||
default="continue",
|
||||
@@ -173,7 +176,7 @@ class BugHunter(ChatWithBreakdownMixin, BaseAgent):
|
||||
if awaiting_user_test:
|
||||
buttons = {"yes": "Yes, the issue is fixed", "no": "No", "start_pair_programming": "Start Pair Programming"}
|
||||
user_feedback = await self.ask_question(
|
||||
"Is the bug you reported fixed now?",
|
||||
BH_IS_BUG_FIXED,
|
||||
buttons=buttons,
|
||||
default="yes",
|
||||
buttons_only=True,
|
||||
@@ -201,7 +204,7 @@ class BugHunter(ChatWithBreakdownMixin, BaseAgent):
|
||||
}
|
||||
)
|
||||
user_feedback = await self.ask_question(
|
||||
"Please add any additional feedback that could help Pythagora solve this bug",
|
||||
BH_ADDITIONAL_FEEDBACK,
|
||||
buttons=buttons,
|
||||
default="continue",
|
||||
extra_info="collect_logs",
|
||||
|
||||
@@ -11,6 +11,7 @@ from core.agents.mixins import ChatWithBreakdownMixin, RelevantFilesMixin
|
||||
from core.agents.response import AgentResponse
|
||||
from core.config import PARSE_TASK_AGENT_NAME, TASK_BREAKDOWN_AGENT_NAME
|
||||
from core.config.actions import (
|
||||
DEV_EXECUTE_TASK,
|
||||
DEV_TASK_BREAKDOWN,
|
||||
DEV_TASK_REVIEW_FEEDBACK,
|
||||
DEV_TASK_START,
|
||||
@@ -329,7 +330,7 @@ class Developer(ChatWithBreakdownMixin, RelevantFilesMixin, BaseAgent):
|
||||
if self.current_state.run_command:
|
||||
await self.ui.send_run_command(self.current_state.run_command)
|
||||
user_response = await self.ask_question(
|
||||
"Do you want to execute the above task?",
|
||||
DEV_EXECUTE_TASK,
|
||||
buttons=buttons,
|
||||
default="yes",
|
||||
buttons_only=True,
|
||||
|
||||
@@ -6,7 +6,7 @@ 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.actions import EX_RUN_COMMAND, EX_SKIP_COMMAND
|
||||
from core.config.actions import EX_RUN_COMMAND, EX_SKIP_COMMAND, RUN_COMMAND
|
||||
from core.llm.parser import JSONParser
|
||||
from core.log import get_logger
|
||||
from core.proc.exec_log import ExecLog
|
||||
@@ -79,9 +79,9 @@ class Executor(BaseAgent):
|
||||
timeout = options.get("timeout")
|
||||
|
||||
if timeout:
|
||||
q = f"Can I run command: {cmd} with {timeout}s timeout?"
|
||||
q = f"{RUN_COMMAND} {cmd} with {timeout}s timeout?"
|
||||
else:
|
||||
q = f"Can I run command: {cmd}?"
|
||||
q = f"{RUN_COMMAND} {cmd}?"
|
||||
|
||||
confirm = await self.ask_question(
|
||||
q,
|
||||
|
||||
@@ -8,7 +8,15 @@ from core.agents.git import GitMixin
|
||||
from core.agents.mixins import FileDiffMixin
|
||||
from core.agents.response import AgentResponse
|
||||
from core.config import FRONTEND_AGENT_NAME
|
||||
from core.config.actions import FE_CONTINUE, FE_INIT, FE_ITERATION, FE_ITERATION_DONE, FE_START
|
||||
from core.config.actions import (
|
||||
FE_CHANGE_REQ,
|
||||
FE_CONTINUE,
|
||||
FE_DONE_WITH_UI,
|
||||
FE_INIT,
|
||||
FE_ITERATION,
|
||||
FE_ITERATION_DONE,
|
||||
FE_START,
|
||||
)
|
||||
from core.llm.parser import DescriptiveCodeBlockParser
|
||||
from core.log import get_logger
|
||||
from core.telemetry import telemetry
|
||||
@@ -171,7 +179,7 @@ class Frontend(FileDiffMixin, GitMixin, BaseAgent):
|
||||
await self.ui.send_project_stage({"stage": ProjectStage.ITERATE_FRONTEND})
|
||||
|
||||
answer = await self.ask_question(
|
||||
"Do you want to change anything or report a bug? Keep in mind that currently ONLY frontend is implemented.",
|
||||
FE_CHANGE_REQ,
|
||||
buttons={
|
||||
"yes": "I'm done building the UI",
|
||||
},
|
||||
@@ -182,7 +190,7 @@ class Frontend(FileDiffMixin, GitMixin, BaseAgent):
|
||||
|
||||
if answer.button == "yes":
|
||||
answer = await self.ask_question(
|
||||
"Are you sure you're done building the UI and want to start building the backend functionality now?",
|
||||
FE_DONE_WITH_UI,
|
||||
buttons={
|
||||
"yes": "Yes, let's build the backend",
|
||||
"no": "No, continue working on the UI",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from core.agents.base import BaseAgent
|
||||
from core.agents.response import AgentResponse, ResponseType
|
||||
from core.config.actions import HUMAN_INTERVENTION_QUESTION
|
||||
|
||||
|
||||
class HumanInput(BaseAgent):
|
||||
@@ -16,7 +17,7 @@ class HumanInput(BaseAgent):
|
||||
description = step["human_intervention_description"]
|
||||
|
||||
await self.ask_question(
|
||||
f"I need human intervention: {description}",
|
||||
f"{HUMAN_INTERVENTION_QUESTION} {description}",
|
||||
buttons={"continue": "Continue"},
|
||||
default="continue",
|
||||
buttons_only=True,
|
||||
|
||||
@@ -9,7 +9,7 @@ from core.agents.convo import AgentConvo
|
||||
from core.agents.mixins import ChatWithBreakdownMixin, IterationPromptMixin, RelevantFilesMixin, TestSteps
|
||||
from core.agents.response import AgentResponse
|
||||
from core.config import TROUBLESHOOTER_GET_RUN_COMMAND
|
||||
from core.config.actions import TS_ALT_SOLUTION, TS_TASK_REVIEWED
|
||||
from core.config.actions import TS_ALT_SOLUTION, TS_APP_WORKING, TS_DESCRIBE_ISSUE, TS_TASK_REVIEWED
|
||||
from core.db.models.file import File
|
||||
from core.db.models.project_state import IterationStatus, TaskStatus
|
||||
from core.llm.parser import JSONParser, OptionalCodeBlockParser
|
||||
@@ -262,7 +262,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
|
||||
while True:
|
||||
await self.ui.send_project_stage({"stage": ProjectStage.GET_USER_FEEDBACK})
|
||||
|
||||
test_message = "Please check if the app is working"
|
||||
test_message = TS_APP_WORKING
|
||||
if user_instructions:
|
||||
hint = " Here is a description of what should be working:\n\n" + user_instructions
|
||||
|
||||
@@ -304,7 +304,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
|
||||
elif user_response.button == "bug":
|
||||
await self.ui.send_project_stage({"stage": ProjectStage.DESCRIBE_ISSUE})
|
||||
user_description = await self.ask_question(
|
||||
"Please describe the issue you found (one at a time) and share any relevant server logs",
|
||||
TS_DESCRIBE_ISSUE,
|
||||
extra_info="collect_logs",
|
||||
buttons={"back": "Back"},
|
||||
)
|
||||
|
||||
@@ -10,15 +10,26 @@ from uuid import UUID
|
||||
|
||||
from core.config import Config, LLMProvider, LocalIPCConfig, ProviderConfig, UIAdapter, get_config, loader
|
||||
from core.config.actions import (
|
||||
BH_ADDITIONAL_FEEDBACK,
|
||||
BH_HUMAN_TEST_AGAIN,
|
||||
BH_IS_BUG_FIXED,
|
||||
BH_START_BUG_HUNT,
|
||||
BH_START_USER_TEST,
|
||||
BH_STARTING_PAIR_PROGRAMMING,
|
||||
BH_WAIT_BUG_REP_INSTRUCTIONS,
|
||||
CM_UPDATE_FILES,
|
||||
DEV_TASK_BREAKDOWN,
|
||||
DEV_TASK_START,
|
||||
DEV_TROUBLESHOOT,
|
||||
FE_CHANGE_REQ,
|
||||
FE_DONE_WITH_UI,
|
||||
HUMAN_INTERVENTION_QUESTION,
|
||||
MIX_BREAKDOWN_CHAT_PROMPT,
|
||||
RUN_COMMAND,
|
||||
TC_TASK_DONE,
|
||||
TL_EDIT_DEV_PLAN,
|
||||
TS_APP_WORKING,
|
||||
TS_DESCRIBE_ISSUE,
|
||||
)
|
||||
from core.config.env_importer import import_from_dotenv
|
||||
from core.config.version import get_version
|
||||
@@ -26,7 +37,7 @@ from core.db.session import SessionManager
|
||||
from core.db.setup import run_migrations
|
||||
from core.log import get_logger, setup
|
||||
from core.state.state_manager import StateManager
|
||||
from core.ui.base import UIBase
|
||||
from core.ui.base import AgentSource, UIBase, UISource
|
||||
from core.ui.console import PlainConsoleUI
|
||||
from core.ui.ipc_client import IPCClientUI
|
||||
from core.ui.virtual import VirtualUI
|
||||
@@ -314,21 +325,107 @@ def trim_logs(logs: str) -> str:
|
||||
return logs
|
||||
|
||||
|
||||
def get_source_for_history(msg_type: Optional[str] = "", question: Optional[str] = ""):
|
||||
if question in [TL_EDIT_DEV_PLAN]:
|
||||
return AgentSource("Tech Lead", "tech-lead")
|
||||
|
||||
if question in [FE_CHANGE_REQ, FE_DONE_WITH_UI]:
|
||||
return AgentSource("Frontend", "frontend")
|
||||
|
||||
elif question in [
|
||||
TS_DESCRIBE_ISSUE,
|
||||
BH_HUMAN_TEST_AGAIN,
|
||||
BH_IS_BUG_FIXED,
|
||||
TS_APP_WORKING,
|
||||
BH_ADDITIONAL_FEEDBACK,
|
||||
] or msg_type in ["instructions", "bh_breakdown"]:
|
||||
return AgentSource("Bug Hunter", "bug-hunter")
|
||||
|
||||
elif msg_type in ["bug_reproduction_instructions", "bug_description"]:
|
||||
return AgentSource("Troubleshooter", "troubleshooter")
|
||||
|
||||
elif HUMAN_INTERVENTION_QUESTION in question:
|
||||
return AgentSource("Human Input", "human-input")
|
||||
|
||||
elif RUN_COMMAND in question:
|
||||
return AgentSource("Executor", "executor")
|
||||
|
||||
elif msg_type in ["task_description", "task_breakdown"]:
|
||||
return AgentSource("Developer", "developer")
|
||||
|
||||
else:
|
||||
return UISource("Pythagora", "pythagora")
|
||||
|
||||
|
||||
async def print_convo(
|
||||
ui: UIBase,
|
||||
convo: list,
|
||||
):
|
||||
for msg in convo:
|
||||
if "bh_breakdown" in msg:
|
||||
await ui.send_message(
|
||||
msg["bh_breakdown"],
|
||||
source=get_source_for_history(msg_type="bh_breakdown"),
|
||||
project_state_id=msg["id"],
|
||||
)
|
||||
|
||||
if "task_description" in msg:
|
||||
await ui.send_message(
|
||||
msg["task_description"],
|
||||
source=get_source_for_history(msg_type="task_description"),
|
||||
project_state_id=msg["id"],
|
||||
)
|
||||
|
||||
if "task_breakdown" in msg:
|
||||
await ui.send_message(
|
||||
msg["task_breakdown"],
|
||||
source=get_source_for_history(msg_type="task_breakdown"),
|
||||
project_state_id=msg["id"],
|
||||
)
|
||||
|
||||
if "test_instructions" in msg:
|
||||
await ui.send_test_instructions(
|
||||
msg["test_instructions"],
|
||||
source=get_source_for_history("test_instructions"),
|
||||
project_state_id=msg["id"],
|
||||
)
|
||||
|
||||
if "files" in msg:
|
||||
for f in msg["files"]:
|
||||
await ui.send_file_status(f["path"], "done")
|
||||
await ui.generate_diff(
|
||||
file_path=f["path"],
|
||||
file_old=f.get("old_content", ""),
|
||||
file_new=f.get("new_content", ""),
|
||||
n_new_lines=f["diff"][0],
|
||||
n_del_lines=f["diff"][1],
|
||||
)
|
||||
|
||||
if "user_inputs" in msg and msg["user_inputs"]:
|
||||
for input_item in msg["user_inputs"]:
|
||||
if "question" in input_item:
|
||||
await ui.send_message(
|
||||
input_item["question"],
|
||||
source=get_source_for_history(question=input_item["question"]),
|
||||
project_state_id=msg["id"],
|
||||
)
|
||||
|
||||
if "answer" in input_item:
|
||||
if input_item["question"] != TL_EDIT_DEV_PLAN:
|
||||
await ui.send_user_input_history(input_item["answer"], project_state_id=msg["id"])
|
||||
|
||||
|
||||
async def load_convo(
|
||||
sm: StateManager,
|
||||
project_id: Optional[UUID] = None,
|
||||
step_index: Optional[int] = None,
|
||||
branch_id: Optional[UUID] = None,
|
||||
) -> list:
|
||||
"""
|
||||
List all projects in the database.
|
||||
"""
|
||||
convo = []
|
||||
|
||||
project_states = await sm.get_project_states(project_id)
|
||||
project_states = [state for state in project_states if 0 <= state.step_index <= step_index]
|
||||
|
||||
branches = await sm.get_branches_for_project_id(project_id)
|
||||
branch_id = branches[0].id
|
||||
project_states = await sm.get_project_states(project_id, branch_id)
|
||||
|
||||
task_counter = 1
|
||||
|
||||
@@ -343,7 +440,39 @@ async def load_convo(
|
||||
convo_el["user_inputs"] = []
|
||||
for ui in user_inputs:
|
||||
if ui.question:
|
||||
if ui.question == MIX_BREAKDOWN_CHAT_PROMPT:
|
||||
if len(state.iterations) > 0:
|
||||
# as it's not available in the current state, take the next state's description - that is the bug description!
|
||||
next_state = project_states[i + 1] if i + 1 < len(project_states) else None
|
||||
if next_state is not None and next_state.iterations is not None:
|
||||
si = next_state.iterations[-1]
|
||||
if si is not None:
|
||||
if si.get("description", None) is not None:
|
||||
convo_el["bh_breakdown"] = si["description"]
|
||||
else:
|
||||
# if there are no iterations, it means developer made task breakdown, take the next state's first task with status = todo
|
||||
next_state = project_states[i + 1] if i + 1 < len(project_states) else None
|
||||
if next_state is not None:
|
||||
task = find_first_todo_task(next_state.tasks)
|
||||
if task.get("test_instructions", None) is not None:
|
||||
convo_el["test_instructions"] = task["test_instructions"]
|
||||
if task.get("instructions", None) is not None:
|
||||
convo_el["task_breakdown"] = task["instructions"]
|
||||
|
||||
if ui.question == BH_HUMAN_TEST_AGAIN:
|
||||
if state.iterations:
|
||||
if state.iterations[0].get("bug_reproduction_description", None) is not None:
|
||||
convo_el["bug_reproduction_description"] = state.iterations[0][
|
||||
"bug_reproduction_description"
|
||||
]
|
||||
|
||||
answer = trim_logs(ui.answer_text) if ui.answer_text is not None else ui.answer_button
|
||||
if answer == "bug":
|
||||
answer = "There is an issue"
|
||||
elif answer == "continue":
|
||||
answer = "Everything works"
|
||||
elif answer == "change":
|
||||
answer = "I want to make a change"
|
||||
convo_el["user_inputs"].append({"question": ui.question, "answer": answer})
|
||||
|
||||
if state.action is not None:
|
||||
@@ -351,31 +480,32 @@ async def load_convo(
|
||||
task_counter = int(state.action.split("#")[1].split()[0])
|
||||
|
||||
elif state.action == DEV_TROUBLESHOOT.format(task_counter):
|
||||
if state.iterations is not None:
|
||||
if state.iterations is not None and len(state.iterations) > 0:
|
||||
si = state.iterations[-1]
|
||||
if si is not None:
|
||||
if si["user_feedback"] is not None:
|
||||
if si.get("user_feedback", None) is not None:
|
||||
convo_el["user_feedback"] = si["user_feedback"]
|
||||
if si["description"] is not None:
|
||||
if si.get("description", None) is not None:
|
||||
convo_el["description"] = si["description"]
|
||||
|
||||
elif state.action == DEV_TASK_BREAKDOWN.format(task_counter):
|
||||
task = state.tasks[task_counter - 1]
|
||||
if "description" in task and task["description"] is not None:
|
||||
if task.get("description", None) is not None:
|
||||
convo_el["description"] = task["description"]
|
||||
|
||||
if "instructions" in task and task["instructions"] is not None:
|
||||
if task.get("instructions", None) is not None:
|
||||
convo_el["instructions"] = task["instructions"]
|
||||
|
||||
elif state.action == TC_TASK_DONE.format(task_counter):
|
||||
if state.tasks:
|
||||
# find the next task description and print it in question
|
||||
next_task = find_first_todo_task(state.tasks)
|
||||
if next_task:
|
||||
convo_el["task_description"] = next_task["description"]
|
||||
task = state.tasks[task_counter - 1]
|
||||
if "test_instructions" in task and task["test_instructions"] is not None:
|
||||
convo_el["test_instructions"] = task["test_instructions"]
|
||||
if next_task is not None and next_task.get("description", None) is not None:
|
||||
convo_el["task_description"] = f"Task #{task_counter} - " + next_task["description"]
|
||||
|
||||
elif state.action == DEV_TASK_START:
|
||||
task = state.tasks[task_counter - 1]
|
||||
if task.get("instructions", None) is not None:
|
||||
convo_el["task_breakdown"] = task["instructions"]
|
||||
|
||||
elif state.action == CM_UPDATE_FILES:
|
||||
files = []
|
||||
@@ -402,25 +532,23 @@ async def load_convo(
|
||||
|
||||
convo_el["files"] = files
|
||||
|
||||
elif state.action == BH_START_BUG_HUNT.format(task_counter):
|
||||
if state.iterations is not None and len(state.iterations) > 0:
|
||||
si = state.iterations[-1]
|
||||
if si is not None:
|
||||
if "user_feedback" in si and si["user_feedback"] is not None:
|
||||
|
||||
if state.action == BH_START_BUG_HUNT.format(task_counter):
|
||||
if si.get("user_feedback", None) is not None:
|
||||
convo_el["user_feedback"] = si["user_feedback"]
|
||||
|
||||
if "description" in si and si["description"] is not None:
|
||||
if si.get("description", None) is not None:
|
||||
convo_el["description"] = si["description"]
|
||||
|
||||
elif state.action == BH_WAIT_BUG_REP_INSTRUCTIONS.format(task_counter):
|
||||
if state.iterations is not None:
|
||||
elif state.action == BH_WAIT_BUG_REP_INSTRUCTIONS.format(task_counter):
|
||||
for si in state.iterations:
|
||||
if "bug_reproduction_description" in si and si["bug_reproduction_description"] is not None:
|
||||
if si.get("bug_reproduction_description", None) is not None:
|
||||
convo_el["bug_reproduction_description"] = si["bug_reproduction_description"]
|
||||
|
||||
elif state.action == BH_START_USER_TEST.format(task_counter):
|
||||
si = state.iterations[-1]
|
||||
if si is not None:
|
||||
if "bug_hunting_cycles" in si and si["bug_hunting_cycles"] is not None:
|
||||
elif state.action == BH_START_USER_TEST.format(task_counter):
|
||||
if si.get("bug_hunting_cycles", None) is not None:
|
||||
cycle = si["bug_hunting_cycles"][-1]
|
||||
if cycle is not None:
|
||||
if "user_feedback" in cycle and cycle["user_feedback"] is not None:
|
||||
@@ -431,49 +559,14 @@ async def load_convo(
|
||||
):
|
||||
convo_el["human_readable_instructions"] = cycle["human_readable_instructions"]
|
||||
|
||||
elif state.action == BH_STARTING_PAIR_PROGRAMMING.format(task_counter):
|
||||
si = state.iterations[-1]
|
||||
if si is not None:
|
||||
elif state.action == BH_STARTING_PAIR_PROGRAMMING.format(task_counter):
|
||||
if "user_feedback" in si and si["user_feedback"] is not None:
|
||||
convo_el["user_feedback"] = si["user_feedback"]
|
||||
if "initial_explanation" in si and si["initial_explanation"] is not None:
|
||||
convo_el["initial_explanation"] = si["initial_explanation"]
|
||||
|
||||
if convo_el.get("user_inputs", None) is not None or convo_el.get("files", None) is not None:
|
||||
for j, ui in enumerate(user_inputs):
|
||||
if ui.question and ui.question == MIX_BREAKDOWN_CHAT_PROMPT:
|
||||
if len(state.tasks) == 1:
|
||||
if state.tasks[0]["instructions"] is not None:
|
||||
convo_el["breakdown"] = state.tasks[task_counter - 1]["instructions"]
|
||||
break
|
||||
elif (
|
||||
state.tasks[task_counter - 1] is not None
|
||||
and state.tasks[task_counter - 1]["instructions"] is not None
|
||||
):
|
||||
convo_el["breakdown"] = state.tasks[task_counter - 1]["instructions"]
|
||||
break
|
||||
elif state.iterations:
|
||||
if (
|
||||
state.iterations[-1].get("bug_hunting_cycles", None) is not None
|
||||
and state.iterations[-1]["bug_hunting_cycles"]
|
||||
and state.iterations[-1]["bug_hunting_cycles"][-1].get("human_readable_instructions", None)
|
||||
is not None
|
||||
):
|
||||
convo_el["breakdown"] = state.iterations[-1]["bug_hunting_cycles"][-1][
|
||||
"human_readable_instructions"
|
||||
]
|
||||
break
|
||||
else:
|
||||
# try to get the next state's instructions from the task
|
||||
next_state = project_states[i + 1]
|
||||
if next_state.tasks is not None:
|
||||
next_task = find_first_todo_task(next_state.tasks)
|
||||
if next_task:
|
||||
convo_el["task_description"] = next_task["description"]
|
||||
break
|
||||
|
||||
convo_el["action"] = state.action
|
||||
convo.append(convo_el)
|
||||
convo_el["action"] = state.action
|
||||
convo.append(convo_el)
|
||||
|
||||
return convo
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import sys
|
||||
from argparse import Namespace
|
||||
from asyncio import run
|
||||
|
||||
from core.config.actions import TL_EDIT_DEV_PLAN
|
||||
|
||||
try:
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.asyncio import AsyncioIntegration
|
||||
@@ -23,6 +21,7 @@ from core.cli.helpers import (
|
||||
list_projects_json,
|
||||
load_convo,
|
||||
load_project,
|
||||
print_convo,
|
||||
show_config,
|
||||
)
|
||||
from core.db.session import SessionManager
|
||||
@@ -37,16 +36,11 @@ from core.ui.base import (
|
||||
UIBase,
|
||||
UIClosedError,
|
||||
UserInput,
|
||||
bug_hunter_source,
|
||||
developer_source,
|
||||
history_source1,
|
||||
history_source2,
|
||||
pythagora_source,
|
||||
)
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
|
||||
telemetry_sent = False
|
||||
source_alt = True
|
||||
|
||||
@@ -207,14 +201,6 @@ async def start_new_project(sm: StateManager, ui: UIBase) -> bool:
|
||||
return project_state is not None
|
||||
|
||||
|
||||
def alternate_source():
|
||||
"""Toggle between pythagora_source and history_source1."""
|
||||
global source_alt
|
||||
source = history_source1 if source_alt else history_source2
|
||||
source_alt = not source_alt
|
||||
return source
|
||||
|
||||
|
||||
async def run_pythagora_session(sm: StateManager, ui: UIBase, args: Namespace):
|
||||
"""
|
||||
Run a Pythagora session.
|
||||
@@ -225,85 +211,15 @@ async def run_pythagora_session(sm: StateManager, ui: UIBase, args: Namespace):
|
||||
:return: True if the application ran successfully, False otherwise.
|
||||
"""
|
||||
|
||||
if args.project and args.step:
|
||||
convo = (await load_convo(sm, args.project, args.step))[-50:]
|
||||
|
||||
for msg in convo:
|
||||
if "breakdown" in msg:
|
||||
await ui.send_message(msg["breakdown"], source=developer_source, project_state_id=msg["id"])
|
||||
|
||||
if "instructions" in msg:
|
||||
await ui.send_message(msg["instructions"], source=bug_hunter_source, project_state_id=msg["id"])
|
||||
|
||||
if "task_description" in msg:
|
||||
await ui.send_message(msg["task_description"], source=developer_source, project_state_id=msg["id"])
|
||||
|
||||
if "user_inputs" in msg and msg["user_inputs"]:
|
||||
for input_item in msg["user_inputs"]:
|
||||
if "question" in input_item:
|
||||
await ui.send_message(
|
||||
input_item["question"], source=alternate_source(), project_state_id=msg["id"]
|
||||
)
|
||||
|
||||
if "answer" in input_item:
|
||||
if input_item["question"] != TL_EDIT_DEV_PLAN:
|
||||
await ui.send_user_input_history(
|
||||
input_item["answer"], source=alternate_source(), project_state_id=msg["id"]
|
||||
)
|
||||
else:
|
||||
await ui.send_message(
|
||||
input_item["question"], source=alternate_source(), project_state_id=msg["id"]
|
||||
)
|
||||
|
||||
if "test_instructions" in msg:
|
||||
await ui.send_test_instructions(
|
||||
msg["test_instructions"], project_state_id=msg["id"], source=alternate_source()
|
||||
)
|
||||
|
||||
if "files" in msg:
|
||||
source = alternate_source()
|
||||
for f in msg["files"]:
|
||||
await ui.send_file_status(f["path"], "done", source=source)
|
||||
await ui.generate_diff(
|
||||
file_path=f["path"],
|
||||
file_old=f.get("old_content", ""),
|
||||
file_new=f.get("new_content", ""),
|
||||
n_new_lines=f["diff"][0],
|
||||
n_del_lines=f["diff"][1],
|
||||
source=source,
|
||||
)
|
||||
|
||||
# Process any other fields in the message
|
||||
for key, value in msg.items():
|
||||
if (
|
||||
key
|
||||
not in [
|
||||
"user_inputs",
|
||||
"action",
|
||||
"id",
|
||||
"test_instructions",
|
||||
"files",
|
||||
"task_description",
|
||||
"breakdown",
|
||||
]
|
||||
and value
|
||||
):
|
||||
if isinstance(value, str):
|
||||
await ui.send_message(f"{key}: {value}", source=alternate_source(), project_state_id=msg["id"])
|
||||
elif isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
if v and isinstance(v, str):
|
||||
await ui.send_message(
|
||||
f"{k}: {v}", source=alternate_source(), project_state_id=msg["id"]
|
||||
)
|
||||
|
||||
log.debug(f"Convo exists: {len(convo) > 0}")
|
||||
|
||||
if args.project or args.branch or args.step:
|
||||
convo = (await load_convo(sm, args.project, args.branch))[-50:]
|
||||
await print_convo(ui, convo)
|
||||
|
||||
telemetry.set("is_continuation", True)
|
||||
success = await load_project(sm, args.project, args.branch, args.step)
|
||||
if not success:
|
||||
return False
|
||||
|
||||
else:
|
||||
success = await start_new_project(sm, ui)
|
||||
if not success:
|
||||
|
||||
@@ -37,9 +37,21 @@ SPEC_CHANGE_FEATURE_STEP_NAME = "Change specification due to new feature"
|
||||
|
||||
TS_TASK_REVIEWED = "Task #{} reviewed"
|
||||
TS_ALT_SOLUTION = "Alternative solution (attempt #{})"
|
||||
TS_APP_WORKING = "Please check if the app is working"
|
||||
|
||||
PS_EPIC_COMPLETE = "Epic {} completed"
|
||||
|
||||
# other constants
|
||||
TL_EDIT_DEV_PLAN = "Open and edit your development plan in the Progress tab"
|
||||
MIX_BREAKDOWN_CHAT_PROMPT = "Are you happy with the breakdown? Now is a good time to ask questions or suggest changes."
|
||||
FE_CHANGE_REQ = (
|
||||
"Do you want to change anything or report a bug? Keep in mind that currently ONLY frontend is implemented."
|
||||
)
|
||||
FE_DONE_WITH_UI = "Are you sure you're done building the UI and want to start building the backend functionality now?"
|
||||
TS_DESCRIBE_ISSUE = "Please describe the issue you found (one at a time) and share any relevant server logs"
|
||||
BH_HUMAN_TEST_AGAIN = "Please test the app again."
|
||||
BH_IS_BUG_FIXED = "Is the bug you reported fixed now?"
|
||||
BH_ADDITIONAL_FEEDBACK = "Please add any additional feedback that could help Pythagora solve this bug"
|
||||
HUMAN_INTERVENTION_QUESTION = "I need human intervention:"
|
||||
RUN_COMMAND = "Can I run command:"
|
||||
DEV_EXECUTE_TASK = "Do you want to execute the above task?"
|
||||
|
||||
@@ -218,16 +218,27 @@ class ProjectState(Base):
|
||||
@staticmethod
|
||||
async def get_project_states(
|
||||
session: "AsyncSession",
|
||||
project_id: UUID,
|
||||
project_id: Optional[UUID] = None,
|
||||
branch_id: Optional[UUID] = None,
|
||||
) -> list["ProjectState"]:
|
||||
from core.db.models import Branch, ProjectState
|
||||
|
||||
branch = await session.execute(select(Branch).where(Branch.project_id == project_id))
|
||||
branch = branch.scalar_one_or_none()
|
||||
branch = None
|
||||
|
||||
project_states_result = await session.execute(select(ProjectState).where(ProjectState.branch_id == branch.id))
|
||||
# project_states_result = await session.execute(select(ProjectState).where(and_(ProjectState.branch_id == branch.id), ProjectState.action.isnot(None)))
|
||||
return project_states_result.scalars().all()
|
||||
if branch_id:
|
||||
branch = await session.execute(select(Branch).where(Branch.id == branch_id))
|
||||
branch = branch.scalar_one_or_none()
|
||||
elif project_id:
|
||||
branch = await session.execute(select(Branch).where(Branch.project_id == project_id))
|
||||
branch = branch.scalar_one_or_none()
|
||||
|
||||
if branch:
|
||||
project_states_result = await session.execute(
|
||||
select(ProjectState).where(ProjectState.branch_id == branch.id)
|
||||
)
|
||||
return project_states_result.scalars().all()
|
||||
|
||||
return []
|
||||
|
||||
async def create_next_state(self) -> "ProjectState":
|
||||
"""
|
||||
|
||||
@@ -69,13 +69,4 @@ class UserInput(Base):
|
||||
)
|
||||
)
|
||||
user_input = user_input.scalars().all()
|
||||
|
||||
if user_input is None:
|
||||
user_input = await session.execute(
|
||||
select(UserInput).where(
|
||||
and_(UserInput.branch_id == branch_id, UserInput.project_state_id == project_state.prev_state_id)
|
||||
)
|
||||
)
|
||||
user_input = user_input.scalars().all()
|
||||
|
||||
return user_input if len(user_input) > 0 else []
|
||||
|
||||
@@ -78,13 +78,9 @@ class StateManager:
|
||||
async with self.session_manager as session:
|
||||
return await Project.get_all_projects(session)
|
||||
|
||||
async def get_convo(self):
|
||||
async def get_project_states(self, project_id: Optional[UUID], branch_id: Optional[UUID]) -> list[ProjectState]:
|
||||
async with self.session_manager as session:
|
||||
return await Project.get_convo(session)
|
||||
|
||||
async def get_project_states(self, project_id: UUID) -> list[ProjectState]:
|
||||
async with self.session_manager as session:
|
||||
return await ProjectState.get_project_states(session, project_id)
|
||||
return await ProjectState.get_project_states(session, project_id, branch_id)
|
||||
|
||||
async def get_branches_for_project_id(self, project_id: UUID) -> list[Branch]:
|
||||
async with self.session_manager as session:
|
||||
|
||||
@@ -491,12 +491,6 @@ class UIBase:
|
||||
|
||||
|
||||
pythagora_source = UISource("Pythagora", "pythagora")
|
||||
|
||||
developer_source = AgentSource("Developer", "developer")
|
||||
bug_hunter_source = AgentSource("Bug Hunter", "bug-hunter")
|
||||
|
||||
history_source1 = UISource("Developer", "developer")
|
||||
history_source2 = UISource("Bug Hunter", "bug-hunter")
|
||||
success_source = UISource("Congratulations", "success")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user