fix conflict

This commit is contained in:
seehi 2024-08-05 20:54:00 +08:00
commit dfccf41a5f
9 changed files with 74 additions and 31 deletions

View file

@ -267,7 +267,6 @@ class WriteDesign(Action):
if not output_pathname:
output_pathname = Path(output_pathname) / "docs" / "sytem_design.json"
output_pathname.mkdir(parents=True, exist_ok=True)
elif not Path(output_pathname).is_absolute():
output_pathname = DEFAULT_WORKSPACE_ROOT / output_pathname
output_pathname = Path(output_pathname)

View file

@ -188,7 +188,6 @@ class WriteTasks(Action):
if not output_pathname:
output_pathname = Path(output_pathname) / "docs" / "project_schedule.json"
output_pathname.mkdir(parents=True, exist_ok=True)
elif not Path(output_pathname).is_absolute():
output_pathname = DEFAULT_WORKSPACE_ROOT / output_pathname
output_pathname = Path(output_pathname)

View file

@ -12,6 +12,7 @@ from metagpt.logs import logger
from metagpt.tools.web_browser_engine import WebBrowserEngine
from metagpt.utils.common import CodeParser
from metagpt.utils.parse_html import WebPage
from metagpt.utils.report import ThoughtReporter
REWRITE_QUERY_PROMPT = """
Role: You are a highly efficient assistant that provide a better search query for web search engine to answer the given question.
@ -263,4 +264,8 @@ class SearchEnhancedQA(Action):
system_prompt = SEARCH_ENHANCED_QA_SYSTEM_PROMPT.format(context=context)
return await self._aask(query, [system_prompt])
async with ThoughtReporter(enable_llm_stream=True) as reporter:
await reporter.async_report({"type": "quick"})
rsp = await self._aask(query, [system_prompt])
return rsp

View file

@ -313,7 +313,6 @@ class WritePRD(Action):
if not output_pathname:
output_pathname = DEFAULT_WORKSPACE_ROOT / "docs" / "prd.json"
output_pathname.mkdir(parents=True, exist_ok=True)
elif not Path(output_pathname).is_absolute():
output_pathname = DEFAULT_WORKSPACE_ROOT / output_pathname
output_pathname = Path(output_pathname)

View file

@ -114,8 +114,8 @@ QUICK_THINK_PROMPT = """
Decide if the latest user message previously is a quick question.
Quick questions include common-sense, legal, logical, math, multiple-choice questions, greetings, or casual chat that you can answer directly.
Questions about you or your team info are also quick questions.
Time- or location-sensitive questions such as wheather or news inquiry are NOT quick questions.
Software development tasks are NOT quick questions.
Time- or location-sensitive questions such as wheather or news inquiry are NOT quick questions. Moreover, you should output a keyword SEARCH to indicate the need for a google search.
Software development tasks are NOT quick questions. Code execution, however trivial, is NOT a quick question.
However, these programming-related tasks are quick questions: writing trivial code snippets (fewer than 30 lines), filling a single function or class, explaining concepts, writing tutorials and documentation.
Respond with a concise thought then a YES if the question is a quick question, otherwise, a NO. Your response:
Respond with a concise thought then a YES if the question is a quick question, otherwise, a NO or a SEARCH. Your response:
"""

View file

@ -20,7 +20,7 @@ Note:
1. If the requirement is a pure DATA-RELATED requirement, such as web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst.
2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager -> writing a System Design by the Architect -> creating tasks by the Project Manager -> and coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement.
2.1. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly.
3. If the requirement is to fix a bug or issue, you should assign it to Issue Solver instead of Engineer.
3. If the requirement is to fix a bug or issue, you should assign it to Issue Solver instead of Engineer. However, if the bug or issue is related to the software developed by the team, you should assign it to Engineer.
4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members.
5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear.
6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) and remind Engineer to definitely read them when publishing message to Engineer.

View file

@ -1,9 +1,12 @@
from __future__ import annotations
from pydantic import Field
from metagpt.actions.write_code_review import ReviewAndRewriteCode
from metagpt.prompts.di.engineer2 import ENGINEER2_INSTRUCTION
from metagpt.roles.di.role_zero import RoleZero
from metagpt.strategy.experience_retriever import ENGINEER_EXAMPLE
from metagpt.tools.libs.terminal import Terminal
class Engineer2(RoleZero):
@ -12,13 +15,16 @@ class Engineer2(RoleZero):
goal: str = "Take on game, app, and web development."
instruction: str = ENGINEER2_INSTRUCTION
tools: list[str] = ["Plan", "Editor:write,read", "RoleZero", "ReviewAndRewriteCode"]
terminal: Terminal = Field(default_factory=Terminal, exclude=True)
tools: list[str] = ["Plan", "Editor:write,read", "RoleZero", "Terminal:run_command", "ReviewAndRewriteCode"]
def _update_tool_execution(self):
review = ReviewAndRewriteCode()
self.tool_execution_map.update(
{
"Terminal.run_command": self.terminal.run_command,
"ReviewAndRewriteCode.run": review.run,
"ReviewAndRewriteCode": review.run,
}

View file

@ -11,6 +11,7 @@ from pydantic import model_validator
from metagpt.actions import Action, UserRequirement
from metagpt.actions.analyze_requirements import AnalyzeRequirementsRestrictions
from metagpt.actions.di.run_command import RunCommand
from metagpt.actions.search_enhanced_qa import SearchEnhancedQA
from metagpt.exp_pool import exp_cache
from metagpt.exp_pool.context_builders import RoleZeroContextBuilder
from metagpt.exp_pool.serializers import RoleZeroSerializer
@ -63,7 +64,6 @@ class RoleZero(Role):
# Equipped with three basic tools by default for optional use
editor: Editor = Editor()
browser: Browser = Browser()
# terminal: Terminal = Terminal() # FIXME: TypeError: cannot pickle '_thread.lock' object
# Experience
experience_retriever: ExpRetriever = DummyExpRetriever()
@ -196,7 +196,7 @@ class RoleZero(Role):
if not self.browser.is_empty_page:
pattern = re.compile(r"Command Browser\.(\w+) executed")
for index, msg in zip(range(len(memory), 0, -1), memory[::-1]):
if pattern.match(msg.content):
if pattern.search(msg.content):
memory.insert(index, UserMessage(cause_by="browser", content=await self.browser.view()))
break
return memory
@ -225,7 +225,7 @@ class RoleZero(Role):
self._set_state(0)
# problems solvable by quick thinking doesn't need to a formal think-act cycle
quick_rsp = await self._quick_think()
quick_rsp, _ = await self._quick_think()
if quick_rsp:
return quick_rsp
@ -245,22 +245,28 @@ class RoleZero(Role):
actions_taken += 1
return rsp # return output from the last action
async def _quick_think(self) -> Message:
async def _quick_think(self) -> Tuple[Message, str]:
answer = ""
rsp_msg = None
if self.rc.news[-1].cause_by != any_to_str(UserRequirement):
# Agents themselves won't generate quick questions, use this rule to reduce extra llm calls
return rsp_msg
return rsp_msg, ""
# routing
memory = self.get_memories(k=4)
memory = self.get_memories(k=4) # FIXME: A magic number for two rounds of Q&A
context = self.llm.format_msg(memory + [UserMessage(content=QUICK_THINK_PROMPT)])
rsp = await self.llm.aask(context)
intent_result = await self.llm.aask(context)
if "yes" in rsp.lower():
if "YES" in intent_result:
# llm call with the original context
async with ThoughtReporter(enable_llm_stream=True) as reporter:
await reporter.async_report({"type": "quick"})
answer = await self.llm.aask(self.llm.format_msg(memory))
elif "SEARCH" in intent_result:
query = "\n".join(str(msg) for msg in memory)
answer = await SearchEnhancedQA().run(query)
if answer:
self.rc.memory.add(AIMessage(content=answer, cause_by=RunCommand))
await self.reply_to_human(content=answer)
rsp_msg = AIMessage(
@ -269,7 +275,7 @@ class RoleZero(Role):
cause_by=RunCommand,
)
return rsp_msg
return rsp_msg, intent_result
async def _check_duplicates(self, req: list[dict], command_rsp: str):
past_rsp = [mem.content for mem in self.rc.memory.get(self.memory_k)]