refactor ask question

This commit is contained in:
LeonOstrez
2025-06-02 14:05:52 +02:00
parent fc23a874b7
commit 5e5fbfe209
12 changed files with 42 additions and 70 deletions

View File

@@ -53,7 +53,7 @@ class BaseAgent:
"""Next state of the project (write-only)."""
return self.state_manager.next_state
async def send_message(self, message: str, extra_info: Optional[str] = None):
async def send_message(self, message: str, extra_info: Optional[dict] = None):
"""
Send a message to the user.
@@ -79,7 +79,7 @@ class BaseAgent:
hint: Optional[str] = None,
verbose: bool = True,
initial_text: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
placeholder: Optional[str] = None,
) -> UserInput:
"""

View File

@@ -169,7 +169,7 @@ class BugHunter(ChatWithBreakdownMixin, BaseAgent):
buttons={"done": "I am done testing"},
buttons_only=True,
default="continue",
extra_info="restart_app",
extra_info={"restart_app": True},
hint="Instructions for testing:\n\n" + test_instructions,
)
@@ -207,7 +207,7 @@ class BugHunter(ChatWithBreakdownMixin, BaseAgent):
BH_ADDITIONAL_FEEDBACK,
buttons=buttons,
default="continue",
extra_info="collect_logs",
extra_info={"collect_logs": True},
hint="Instructions for testing:\n\n" + test_instructions,
)

View File

@@ -89,7 +89,7 @@ class Executor(BaseAgent):
default="yes",
buttons_only=False,
initial_text=cmd,
extra_info="remove_button_yes",
extra_info={"remove_button": "yes"},
)
if confirm.button == "no":
log.info(f"Skipping command execution of `{cmd}` (requested by user)")

View File

@@ -152,7 +152,7 @@ class Frontend(FileDiffMixin, GitMixin, BaseAgent):
"Do you want to change anything or report a bug?" if frontend_only else FE_CHANGE_REQ,
buttons={"yes": "I'm done building the UI"} if not frontend_only else None,
default="yes",
extra_info="restart_app/collect_logs",
extra_info={"restart_app": True, "collect_logs": True},
placeholder='For example, "I don\'t see anything when I open http://localhost:5173/" or "Nothing happens when I click on the NEW PROJECT button"',
)

View File

@@ -348,7 +348,7 @@ class TechLead(RelevantFilesMixin, BaseAgent):
# buttons={"done_editing": "I'm done editing, the plan looks good"},
# default="done_editing",
# buttons_only=True,
# extra_info="edit_plan",
# extra_info={"edit_plan": True},
# )
#
# self.update_epics_and_tasks(response.text)

View File

@@ -273,7 +273,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
is_loop = False
should_iterate = True
should_redo = False
extra_info = "restart_app" if not self.current_state.iterations else None
extra_info = {"restart_app": True} if not self.current_state.iterations else None
while True:
await self.ui.send_project_stage({"stage": ProjectStage.GET_USER_FEEDBACK})
@@ -326,7 +326,7 @@ class Troubleshooter(ChatWithBreakdownMixin, IterationPromptMixin, RelevantFiles
await self.ui.send_project_stage({"stage": ProjectStage.DESCRIBE_ISSUE})
user_description = await self.ask_question(
TS_DESCRIBE_ISSUE,
extra_info="collect_logs",
extra_info={"collect_logs": True},
buttons={"back": "Back"},
)
if user_description.button == "back":

View File

@@ -305,7 +305,7 @@ class BaseLLMClient:
"",
buttons={},
buttons_only=True,
extra_info="not_enough_tokens",
extra_info={"not_enough_tokens": True},
source=pythagora_source,
)
sys.exit(0)
@@ -314,7 +314,7 @@ class BaseLLMClient:
# 'Not enough tokens left, please top up your account and press "Continue".',
# buttons={"continue": "Continue", "exit": "Exit"},
# buttons_only=True,
# extra_info="not_enough_tokens",
# extra_info={"not_enough_tokens": True},
# source=pythagora_source,
# )
# if user_response.button == "continue":

View File

@@ -154,7 +154,7 @@ class UIBase:
*,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
):
"""
Send a complete message to the UI.
@@ -222,7 +222,7 @@ class UIBase:
initial_text: Optional[str] = None,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
placeholder: Optional[str] = None,
) -> UserInput:
"""

View File

@@ -51,7 +51,7 @@ class PlainConsoleUI(UIBase):
*,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
):
if source:
print(f"[{source}] {message}")
@@ -95,7 +95,7 @@ class PlainConsoleUI(UIBase):
initial_text: Optional[str] = None,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
placeholder: Optional[str] = None,
) -> UserInput:
if source:

View File

@@ -22,8 +22,6 @@ class MessageType(str, Enum):
EXIT = "exit"
STREAM = "stream"
VERBOSE = "verbose"
BUTTONS = "button"
BUTTONS_ONLY = "buttons-only"
RESPONSE = "response"
USER_INPUT_REQUEST = "user_input_request"
INFO = "info"
@@ -33,9 +31,7 @@ class MessageType(str, Enum):
APP_LINK = "appLink"
OPEN_FILE = "openFile"
PROJECT_STATS = "projectStats"
HINT = "hint"
KEY_EXPIRED = "keyExpired"
INPUT_PREFILL = "inputPrefill"
LOADING_FINISHED = "loadingFinished"
PROJECT_DESCRIPTION = "projectDescription"
FEATURES_LIST = "featuresList"
@@ -93,7 +89,7 @@ class Message(BaseModel):
category: Optional[str] = None
full_screen: Optional[bool] = False
project_state_id: Optional[str] = None
extra_info: Optional[str] = None
extra_info: Optional[dict] = None
content: Union[str, dict, None] = None
placeholder: Optional[str] = None
accessToken: Optional[str] = None
@@ -255,7 +251,7 @@ class IPCClientUI(UIBase):
*,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
):
if not self.writer:
return
@@ -321,7 +317,7 @@ class IPCClientUI(UIBase):
initial_text: Optional[str] = None,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
placeholder: Optional[str] = None,
) -> UserInput:
if not self.writer:
@@ -329,23 +325,26 @@ class IPCClientUI(UIBase):
category = source.type_name if source else None
if not extra_info:
extra_info = {}
if hint:
await self._send(
MessageType.HINT,
content=hint,
category=category,
project_state_id=project_state_id,
extra_info=extra_info,
)
extra_info["hint"] = hint
elif verbose:
await self._send(
MessageType.VERBOSE,
content=question,
category=category,
project_state_id=project_state_id,
# DO NOT SEND extra_info HERE! It is enough to send it with user_input_request
# extra_info=extra_info,
)
extra_info["verbose"] = question
if buttons:
buttons_str = "/".join(buttons.values())
extra_info["buttons"] = buttons_str
extra_info["buttons_only"] = False
if buttons_only:
extra_info["buttons_only"] = True
if initial_text:
extra_info["initial_text"] = initial_text
if full_screen:
extra_info["full_screen"] = True
await self._send(
MessageType.USER_INPUT_REQUEST,
@@ -355,35 +354,6 @@ class IPCClientUI(UIBase):
extra_info=extra_info,
placeholder=placeholder,
)
if buttons:
buttons_str = "/".join(buttons.values())
if buttons_only:
await self._send(
MessageType.BUTTONS_ONLY,
content=buttons_str,
category=category,
project_state_id=project_state_id,
full_screen=full_screen,
extra_info=extra_info,
)
else:
await self._send(
MessageType.BUTTONS,
content=buttons_str,
category=category,
project_state_id=project_state_id,
full_screen=full_screen,
extra_info=extra_info,
)
if initial_text:
# FIXME: add this to base and console and document it after merging with hint PR
await self._send(
MessageType.INPUT_PREFILL,
content=initial_text,
category=category,
project_state_id=project_state_id,
extra_info=extra_info,
)
response = await self._receive()

View File

@@ -49,7 +49,7 @@ class VirtualUI(UIBase):
*,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
):
if source:
print(f"[{source}] {message}")
@@ -92,7 +92,7 @@ class VirtualUI(UIBase):
initial_text: Optional[str] = None,
source: Optional[UISource] = None,
project_state_id: Optional[str] = None,
extra_info: Optional[str] = None,
extra_info: Optional[dict] = None,
placeholder: Optional[str] = None,
) -> UserInput:
if source:

View File

@@ -92,7 +92,9 @@ async def test_send_message():
connected = await ui.start()
assert connected is True
await ui.send_message("Hello from the other side ♫", source=src, project_state_id="123", extra_info="test")
await ui.send_message(
"Hello from the other side ♫", source=src, project_state_id="123", extra_info={"test": True}
)
await ui.stop()
assert messages == [
@@ -102,7 +104,7 @@ async def test_send_message():
"category": "agent:product-owner",
"project_state_id": "123",
"full_screen": False,
"extra_info": "test",
"extra_info": {"test": True},
"placeholder": None,
"accessToken": None,
"request_id": None,