Fix most of the history print errors

This commit is contained in:
mijauexe
2025-03-31 14:25:41 +02:00
parent 2f4e2ed6a5
commit cf0409d28a
13 changed files with 223 additions and 197 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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"},
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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