update code

This commit is contained in:
stellahsr 2023-10-09 19:32:50 +08:00
parent f70ba27d35
commit 37a7a96bbe
13 changed files with 255 additions and 215 deletions

View file

@ -2,8 +2,6 @@
# @Date : 2023/9/23 12:45
# @Author : stellahong (stellahong@fuzhi.ai)
# @Desc :
import copy
from metagpt.logs import logger
from metagpt.roles.minecraft.minecraft_base import Minecraft as Base
from metagpt.schema import Message, HumanMessage, SystemMessage
@ -40,14 +38,13 @@ class ActionDeveloper(Base):
# Initialize actions specific to the Action role
self._init_actions([GenerateActionCode])
# Set events or actions the ActionAgent should watch or be aware of
# 需要根据events进行自己chest_observation的更新
self._watch([RetrieveSkills])
self.rollout_num_iter = 0
self.task_max_retries = 4
self.finish_state = len(self._actions)
self.critic_reviewer = None # self._rc.env.roles["Task Reviewer"]
self.critic_reviewer = None # self._rc.env.roles["Task Reviewer"]
def render_system_message(self, skills=[], *args, **kwargs):
"""
@ -208,6 +205,7 @@ class ActionDeveloper(Base):
async def handle_add_new_skills(
self, task, program_name, program_code, skills, *args, **kwargs
):
skills = self.game_memory.skills
skill_desp = self.game_memory.skill_desp
new_skills_info = await AddNewSkills().run(
task, program_name, program_code, skills, skill_desp
@ -231,11 +229,9 @@ class ActionDeveloper(Base):
context = self.game_memory.context
# 更新生成的代码和对应程序名称
code, program_name = await GenerateActionCode().run(
program_code, code, program_name = await GenerateActionCode().run(
human_msg, system_msg, *args, **kwargs
)
# logger.warning(type(code))
# logger.info(f"Code is Here:{code}")
if code is not None:
# fixme若有独立的mc code执行入口函数使用独立的函数
@ -298,6 +294,8 @@ class ActionDeveloper(Base):
"success": self.game_memory.runtime_status,
}
logger.info(f"info is {info}")
self.perform_game_info_callback(program_code, self.game_memory.update_program_code)
self.perform_game_info_callback(code, self.game_memory.update_code)
self.perform_game_info_callback(
program_name, self.game_memory.update_program_name
@ -306,11 +304,10 @@ class ActionDeveloper(Base):
return system_msg, human_msg, 0, done, info
async def generate_action_code(self, human_msg, system_msg, *args, **kwargs):
code, program_name = await GenerateActionCode().run(
program_code, code, program_name = await GenerateActionCode().run(
human_msg, system_msg, *args, **kwargs
)
# logger.warning(type(code))
# logger.info(f"Code is Here:{code}")
self.perform_game_info_callback(program_code, self.game_memory.update_program_code)
self.perform_game_info_callback(code, self.game_memory.update_code)
self.perform_game_info_callback(
program_name, self.game_memory.update_program_name

View file

@ -18,29 +18,29 @@ class CurriculumDesigner(Base):
"""
CurriculumDesigner is the automatic curriculum in paper, refer to the code voyager/agents/curriculum.py
"""
def __init__(
self,
name: str = "David",
profile: str = "Expertise in minecraft task design and curriculum development.",
goal: str = " Collect and integrate learner feedback to improve and refine educational content and pathways",
constraints: str = "Limited budget and resources for the development of educational content and technology tools.",
self,
name: str = "David",
profile: str = "Expertise in minecraft task design and curriculum development.",
goal: str = " Collect and integrate learner feedback to improve and refine educational content and pathways",
constraints: str = "Limited budget and resources for the development of educational content and technology tools.",
) -> None:
super().__init__(name, profile, goal, constraints)
# Initialize actions specific to the Action role
self._init_actions([DesignTask, DesignCurriculum])
# Set events or actions the ActionAgent should watch or be aware of
self._watch([PlayerActions, DesignTask])
logger.info(self._actions)
self.finish_state = len(self._actions)
def render_curriculum_observation(self, *, events, chest_observation):
"""
Returns: observation for curriculum
Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/curriculum.py
"""
assert events[-1][0] == "observe", "Last event must be observe"
event = events[-1][1]
biome = event["status"]["biome"]
@ -54,31 +54,31 @@ class CurriculumDesigner(Base):
equipment = event["status"]["equipment"]
inventory_used = event["status"]["inventoryUsed"]
inventory = event["inventory"]
if not any(
"dirt" in block
or "log" in block
or "grass" in block
or "sand" in block
or "snow" in block
for block in voxels
"dirt" in block
or "log" in block
or "grass" in block
or "sand" in block
or "snow" in block
for block in voxels
):
biome = "underground"
other_blocks = ", ".join(
list(
set(block_records).difference(set(voxels).union(set(inventory.keys())))
)
)
other_blocks = other_blocks if other_blocks else "None"
nearby_entities = (
", ".join([k for k, v in sorted(entities.items(), key=lambda x: x[1])])
if entities
else "None"
)
completed_tasks = (
", ".join(self.game_memory.completed_tasks)
if self.game_memory.completed_tasks
@ -89,18 +89,18 @@ class CurriculumDesigner(Base):
if self.game_memory.failed_tasks
else "None"
)
# filter out optional inventory items if required
if (
self.game_memory.progress
< self.game_memory.warm_up["optional_inventory_items"]
self.game_memory.progress
< self.game_memory.warm_up["optional_inventory_items"]
):
inventory = {
k: v
for k, v in inventory.items()
if self.game_memory.core_inv_items_regex.search(k) is not None
}
observation = {
"context": "",
"biome": f"Biome: {biome}\n\n",
@ -118,25 +118,31 @@ class CurriculumDesigner(Base):
"failed_tasks": f"Failed tasks that are too hard: {failed_tasks}\n\n",
}
return observation
# --------------------------------Design Task Prepare---------------------------------------
def render_design_task_human_message(
self, events, chest_observation, *args, **kwargs
async def render_design_task_human_message(
self, events, chest_observation, *args, **kwargs
):
"""
Returns: observation for curriculum
Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/curriculum.py
"""
content = ""
warm_up = self.game_memory.mf_instance.warm_up
observation = self.render_curriculum_observation(
events=events, chest_observation=chest_observation
)
if self.game_memory.progress >= warm_up["context"]:
questions, answers = DesignCurriculum.generate_qa(
# if self.game_memory.progress >= 0: # TEST ONLY
human_msg = self.render_design_curriculum_human_message(
events=events, chest_observation=chest_observation
).content
system_msg = [self.render_design_curriculum_system_message().content]
questions, answers = await self.curriculum_design_action.generate_qa(
events=events, human_msg=human_msg, system_msg=system_msg
)
logger.debug(f"Generate_qa result is HERE: Ques: {questions}, Ans: {answers}")
i = 1
for question, answer in zip(questions, answers):
if "Answer: Unknown" in answer or "language model" in answer:
@ -146,7 +152,7 @@ class CurriculumDesigner(Base):
i += 1
if i > 5:
break
for key in CURRICULUM_OB:
if self.game_memory.progress >= warm_up[key]:
if warm_up[key] != 0:
@ -155,20 +161,20 @@ class CurriculumDesigner(Base):
should_include = True
if should_include:
content += observation[key]
logger.info(f"Curriculum Agent human message\n{content}")
return HumanMessage(content=content)
def render_design_task_system_message(self, *args, **kwargs):
return SystemMessage(content=load_prompt("curriculum"))
def encapsule_design_task_message(self, events, chest_observation, *args, **kwargs):
human_msg = self.render_design_task_human_message(
async def encapsule_design_task_message(self, events, chest_observation, *args, **kwargs):
human_msg = await self.render_design_task_human_message(
events=events, chest_observation=chest_observation, *args, **kwargs
)
system_msg = self.render_design_task_system_message(*args, **kwargs)
return {"system_msg": [system_msg.content], "human_msg": human_msg.content}
def generate_task_if_inventory_full(self, events, chest_observation):
"""
TODO: Try if this could be done with prompt
@ -187,15 +193,15 @@ class CurriculumDesigner(Base):
else:
task = "Craft 1 chest"
return task
# -----------------------------------------------------------------------------------------
# --------------------------------Design Curriculum Prepare--------------------------------
def render_design_curriculum_system_message(self, *args, **kwargs):
return SystemMessage(content=load_prompt("curriculum_qa_step1_ask_questions"))
def render_design_curriculum_human_message(
self, events, chest_observation, *args, **kwargs
self, events, chest_observation, *args, **kwargs
):
observation = self.render_curriculum_observation(
events=events, chest_observation=chest_observation
@ -204,16 +210,16 @@ class CurriculumDesigner(Base):
for key in CURRICULUM_OB:
content += observation[key]
return HumanMessage(content=content)
def encapsule_design_curriculum_message(
self, events, chest_observation, *args, **kwargs
self, events, chest_observation, *args, **kwargs
):
human_msg = self.render_design_curriculum_human_message(
events=events, chest_observation=chest_observation, *args, **kwargs
)
system_msg = self.render_design_curriculum_system_message(*args, **kwargs)
return {"system_msg": [system_msg.content], "human_msg": human_msg.content}
def generate_context_if_inventory_full(self, events, chest_observation):
"""
TODO: Try if this could be done with prompt
@ -244,9 +250,9 @@ class CurriculumDesigner(Base):
else:
context = "Craft 1 chest with 8 planks of any kind of wood."
return context
# -----------------------------------------------------------------------------------------
async def handle_task_design(self, human_msg, system_msg, *args, **kwargs):
"""
Args:
@ -260,7 +266,7 @@ class CurriculumDesigner(Base):
events = self.game_memory.event
chest_observation = self.game_memory.chest_observation
inventoryUsed = events[-1][1]["status"]["inventoryUsed"]
if self.game_memory.progress == 0:
task = self.game_memory.current_task
elif inventoryUsed >= 33:
@ -270,12 +276,12 @@ class CurriculumDesigner(Base):
else:
task = await DesignTask().run(human_msg, system_msg, *args, **kwargs)
logger.info(f"Handle_task_design result is Here: {task}")
self.perform_game_info_callback(task, self.game_memory.update_task)
return Message(
content=f"{task}", instruct_content="task_design", role=self.profile
)
async def handle_curriculum_design(self, human_msg, system_msg, *args, **kwargs):
"""
refer to the context generation in voyager
@ -292,7 +298,7 @@ class CurriculumDesigner(Base):
chest_observation = self.game_memory.chest_observation
inventoryUsed = events[-1][1]["status"]["inventoryUsed"]
task = self.game_memory.current_task
if self.game_memory.progress == 0:
context = self.game_memory.context
elif inventoryUsed >= 33:
@ -300,37 +306,34 @@ class CurriculumDesigner(Base):
self, events=events, chest_observation=chest_observation
)
else:
context = await DesignCurriculum().run(
context = await self.DesignCurriculum().run(
task, human_msg, system_msg, *args, **kwargs
)
self.perform_game_info_callback(context, self.game_memory.update_context)
return Message(
content=f"{context}",
instruct_content="curriculum_design",
role=self.profile,
)
async def _act(self) -> Message:
todo = self._rc.todo
logger.debug(f"Todo is {todo}")
self.maintain_actions(todo)
self.maintain_actions(todo)
# 获取最新的游戏周边环境信息
# events = await self._obtain_events()
events = self.game_memory.event
chest_observation = self.game_memory.chest_observation
# DesignCurriculum.set_qa_cache(self.game_memory.qa_cache)
# msg = self._rc.memory.get(k=1)[0]
# query = msg.content
design_task_message = self.encapsule_design_task_message(
design_task_message = await self.encapsule_design_task_message(
events, chest_observation
)
design_curriculum_message = self.encapsule_design_curriculum_message(
events, chest_observation
)
handler_map = {
DesignTask: self.handle_task_design,
DesignCurriculum: self.handle_curriculum_design,
@ -345,5 +348,5 @@ class CurriculumDesigner(Base):
msg.round_id = self.round_id
self._publish_message(msg)
return msg
raise ValueError(f"Unknown todo type: {type(todo)}")

View file

@ -19,41 +19,40 @@ from metagpt.utils.minecraft import load_prompt
@agent_registry.register("skill_manager")
class SkillManager(Base):
def __init__(
self,
name: str = "John",
profile: str = "Skills Management Specialist",
goal: str = "To oversee and optimize the acquisition, development, and utilization of skills within the organization, ensuring workforce competence and efficiency.",
constraints: str = "Resource allocation, training budgets, and alignment with organizational goals.",
self,
name: str = "John",
profile: str = "Skills Management Specialist",
goal: str = "To oversee and optimize the acquisition, development, and utilization of skills within the organization, ensuring workforce competence and efficiency.",
constraints: str = "Resource allocation, training budgets, and alignment with organizational goals.",
) -> None:
super().__init__(name, profile, goal, constraints)
# Initialize actions specific to the SkillManager role
self._init_actions([RetrieveSkills, GenerateSkillDescription, AddNewSkills]) #AddNewSkills])#先去掉add
self._init_actions([RetrieveSkills, GenerateSkillDescription, AddNewSkills])
# Set events or actions the SkillManager should watch or be aware of
self._watch(
[DesignCurriculum, GenerateActionCode, RetrieveSkills, GenerateSkillDescription]
)
self.finish_state = len(self._actions)
def encapsule_message(self, program_code, program_name, *args, **kwargs):
system_msg = self.render_system_message(load_prompt("skill"))
human_msg = self.render_human_message(
program_code + "\n\n" + f"The main function is `{program_name}`."
)
return {"system_msg": [system_msg.content], "human_msg": human_msg.content}
async def retrieve_skills(self, query, skills, *args, **kwargs):
retrieve_skills = await RetrieveSkills().run(query, skills)
logger.info(f"Render Action Agent system message with {len(retrieve_skills)} skills")
self.perform_game_info_callback(retrieve_skills, self.game_memory.update_retrieve_skills)
return Message(content=f"{retrieve_skills}", instruct_content="retrieve_skills",
return Message(content=f"{retrieve_skills}", instruct_content="retrieve_skills",
role=self.profile, send_to=agent_registry.entries["action_developer"]()._setting.name)
# return Message(
# content=f"{skills}", instruct_content="retrieve_skills", role=self.profile
# ) # Unit test only
async def generate_skill_descp(self, human_msg, system_msg, *args, **kwargs):
program_name = self.game_memory.program_name
desp = await GenerateSkillDescription().run(program_name, human_msg, system_msg)
@ -63,16 +62,16 @@ class SkillManager(Base):
instruct_content="generate_skill_descp",
role=self.profile,
)
async def handle_add_new_skills(
self, task, program_name, program_code, skills, *args, **kwargs
self, task, program_name, program_code, skills, *args, **kwargs
):
if not self.game_memory.runtime_status:
return Message(
content="",
instruct_content="handle_add_new_skills",
role=self.profile,
)
content="",
instruct_content="handle_add_new_skills",
role=self.profile,
)
skill_desp = self.game_memory.skill_desp
new_skills_info = await AddNewSkills().run(
@ -84,43 +83,41 @@ class SkillManager(Base):
instruct_content="handle_add_new_skills",
role=self.profile,
)
async def _act(self) -> Message:
todo = self._rc.todo
logger.debug(f"Todo is {todo}")
self.maintain_actions(todo)
self.maintain_actions(todo)
# 获取最新的游戏周边信息
context = self.game_memory.context
task = self.game_memory.current_task
code = self.game_memory.code
self.perform_game_info_callback(self.game_memory.event, self.game_memory.summarize_chatlog)
event_summary = self.game_memory.event_summary
try:
program_code = code["program_code"] # TODO: Handle code is None, cuz first round DesignCurriculum(code is None) trigger this
except (KeyError, TypeError):
program_code = ""
program_code = self.game_memory.program_code
program_name = self.game_memory.program_name
skills = self.game_memory.skills
# msg = self._rc.memory.get(k=1)[0]
retrieve_skills_message_step1 = {"query": context, "skills": skills}
logger.info(f"check query {context}")
logger.info(f"check event summary {event_summary}")
retrieve_skills_message_step2 = {"query": context + "\n\n" + event_summary, "skills": skills}
generate_skill_message = self.encapsule_message(program_code, program_name)
add_new_skills_message = {
"task": task,
"program_name": program_name,
"program_code": program_code,
"skills": skills,
}
handler_map = {
DesignCurriculum: self.retrieve_skills,
RetrieveSkills: self.retrieve_skills,
@ -139,10 +136,10 @@ class SkillManager(Base):
msg = await handler(**generate_skill_message)
else:
msg = await handler(**add_new_skills_message)
msg.cause_by = type(todo)
msg.round_id = self.round_id
self._publish_message(msg)
return msg
raise ValueError(f"Unknown todo type: {type(todo)}")