remove task_type and parse_browser_action to DataAnalyst

This commit is contained in:
lidanyang 2024-07-10 11:29:27 +08:00
parent be607ba3e3
commit b03ce58fde
5 changed files with 46 additions and 67 deletions

View file

@ -1,15 +1,18 @@
from __future__ import annotations
import re
from typing import List
from pydantic import Field, model_validator
from metagpt.actions.di.execute_nb_code import ExecuteNbCode
from metagpt.actions.di.write_analysis_code import WriteAnalysisCode
from metagpt.logs import logger
from metagpt.prompts.di.data_analyst import BROWSER_INSTRUCTION
from metagpt.prompts.di.data_analyst import BROWSER_INSTRUCTION, TASK_TYPE_DESC, CODE_STATUS
from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION
from metagpt.roles.di.role_zero import RoleZero
from metagpt.schema import TaskResult, Message
from metagpt.strategy.experience_retriever import ExpRetriever, WebExpRetriever
from metagpt.strategy.experience_retriever import ExpRetriever, KeywordExpRetriever
from metagpt.tools.tool_recommend import BM25ToolRecommender, ToolRecommender
from metagpt.tools.tool_registry import register_tool
@ -20,11 +23,12 @@ class DataAnalyst(RoleZero):
profile: str = "DataAnalyst"
goal: str = "Take on any data-related tasks, such as data analysis, machine learning, deep learning, web browsing, web scraping, web searching, web deployment, terminal operation, git and github operation, etc."
instruction: str = ROLE_INSTRUCTION + BROWSER_INSTRUCTION
task_type_desc: str = TASK_TYPE_DESC
tools: list[str] = ["Plan", "DataAnalyst", "RoleZero", "Browser"]
custom_tools: list[str] = ["machine learning", "web scraping", "Terminal"]
custom_tool_recommender: ToolRecommender = None
experience_retriever: ExpRetriever = WebExpRetriever()
experience_retriever: ExpRetriever = KeywordExpRetriever()
use_reflection: bool = True
write_code: WriteAnalysisCode = Field(default_factory=WriteAnalysisCode, exclude=True)
@ -40,6 +44,17 @@ class DataAnalyst(RoleZero):
"DataAnalyst.write_and_exec_code": self.write_and_exec_code,
})
def parse_browser_actions(self, memory: List[Message]):
for index, msg in enumerate(memory):
if msg.cause_by == "browser":
browser_url = re.search('URL: (.*?)\\n', msg.content).group(1)
pattern = re.compile(r"Command Browser\.(\w+) executed")
browser_action = {
'command': pattern.match(memory[index - 1].content).group(1),
'current url': browser_url
}
self.browser_actions.append(browser_action)
async def write_and_exec_code(self):
"""Write a code block for current task and execute it in an interactive notebook environment."""
counter = 0
@ -68,7 +83,7 @@ class DataAnalyst(RoleZero):
tool_info=tool_info,
working_memory=self.rc.working_memory.get() if use_reflection else None,
use_reflection=use_reflection,
browser_memory=self.browser_memory
browser_actions=self.browser_actions
)
self.rc.working_memory.add(Message(content=code, role="assistant", cause_by=WriteAnalysisCode))
@ -83,11 +98,8 @@ class DataAnalyst(RoleZero):
if success:
task_result = TaskResult(code=code, result=result, is_success=success)
self.planner.current_task.update_task_result(task_result)
output = f"""
**Code written**:
{code}
**Execution status**:{'Success' if success else 'Failed'}
**Execution result**: {result}
"""
status = 'Success' if success else 'Failed'
output = CODE_STATUS.format(code=code, status=status, result=result)
self.rc.working_memory.clear()
return output

View file

@ -6,7 +6,6 @@ import re
import traceback
from typing import Callable, Dict, List, Literal, Tuple
from metagpt.strategy.task_type import TaskType
from pydantic import model_validator
from metagpt.actions import Action
@ -41,6 +40,7 @@ class RoleZero(Role):
system_msg: list[str] = None # Use None to conform to the default value at llm.aask
cmd_prompt: str = CMD_PROMPT
instruction: str = ROLE_INSTRUCTION
task_type_desc: str = None
# React Mode
react_mode: Literal["react"] = "react"
@ -54,7 +54,7 @@ class RoleZero(Role):
# Equipped with three basic tools by default for optional use
editor: Editor = Editor()
browser: Browser = Browser()
browser_memory: list[dict] = [] # store the memory of browser
browser_actions: list[dict] = [] # store the browser history actions
# terminal: Terminal = Terminal() # FIXME: TypeError: cannot pickle '_thread.lock' object
# Experience
@ -137,7 +137,6 @@ class RoleZero(Role):
### 2. Plan Status ###
plan_status, current_task = self._get_plan_status()
task_type_desc = "\n".join([f"- **{tt.type_name}**: {tt.value.desc}" for tt in TaskType])
### 3. Tool/Command Info ###
tools = await self.tool_recommender.recommend_tools()
@ -150,19 +149,16 @@ class RoleZero(Role):
example=example,
available_commands=tool_info,
instruction=self.instruction.strip(),
task_type_desc=task_type_desc,
task_type_desc=self.task_type_desc,
)
memory = self.rc.memory.get(self.memory_k)
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):
content = await self.browser.view()
memory.insert(index, UserMessage(cause_by="browser", content=content))
browser_url = re.search('URL: (.*?)\\n', content).group(1)
browser_action = {'command': pattern.match(msg.content).group(1), 'current url': browser_url}
self.browser_memory.append(browser_action)
memory.insert(index, UserMessage(cause_by="browser", content=await self.browser.view()))
break
self.parse_browser_actions(memory=memory)
context = self.llm.format_msg(memory + [UserMessage(content=prompt)])
# print(*context, sep="\n" + "*" * 5 + "\n")
async with ThoughtReporter(enable_llm_stream=True):
@ -171,6 +167,9 @@ class RoleZero(Role):
return True
def parse_browser_actions(self, memory: List[Message]):
pass
async def _act(self) -> Message:
if self.use_fixed_sop:
return await super()._act()