update code

This commit is contained in:
stellahsr 2023-10-11 22:20:27 +08:00
parent e6a5ae938a
commit b55a080c83
6 changed files with 182 additions and 167 deletions

View file

@ -92,7 +92,7 @@ class DesignCurriculum(Action):
def __init__(self, name="", context=None, llm=None):
super().__init__(name, context, llm)
async def generate_qa(self, events, qa_cache, human_msg, system_msg):
async def generate_qa(self, events, qa_cache, qa_cache_questions_vectordb, human_msg, system_msg):
"""
Generate qa for DesignTask's HumanMessage
"""
@ -104,9 +104,9 @@ class DesignCurriculum(Action):
questions = []
answers = []
for question in questions_new:
if self.qa_cache_questions_vectordb._collection.count() > 0:
if qa_cache_questions_vectordb._collection.count() > 0:
docs_and_scores = (
self.qa_cache_questions_vectordb.similarity_search_with_score(
qa_cache_questions_vectordb.similarity_search_with_score(
question, k=1
)
)
@ -120,12 +120,12 @@ class DesignCurriculum(Action):
answer = await self.generate_qa_step2(question=question)
assert question not in qa_cache
qa_cache[question] = answer
self.qa_cache_questions_vectordb.add_texts(
qa_cache_questions_vectordb.add_texts(
texts=[question],
)
with open(f"{CKPT_DIR}/curriculum/qa_cache.json", "w") as f:
json.dump(qa_cache, f)
self.qa_cache_questions_vectordb.persist()
qa_cache_questions_vectordb.persist()
questions.append(question)
answers.append(answer)
assert len(questions_new) == len(questions) == len(answers)
@ -170,7 +170,7 @@ class DesignCurriculum(Action):
# logger.info(f"Curriculum Agent generate_qa_step2 answer: {answer}")
return answer
async def get_context_from_task(self, task, qa_cache):
async def get_context_from_task(self, task, qa_cache, qa_cache_questions_vectordb):
"""
Args: task
Returns: context: "Question: {question}\n{answer}"
@ -186,16 +186,16 @@ class DesignCurriculum(Action):
else:
answer = await self.generate_qa_step2(question=question)
qa_cache[question] = answer
self.qa_cache_questions_vectordb.add_texts(
qa_cache_questions_vectordb.add_texts(
texts=[question],
)
with open(f"{CKPT_DIR}/curriculum/qa_cache.json", "w") as f:
json.dump(qa_cache, f)
self.qa_cache_questions_vectordb.persist()
qa_cache_questions_vectordb.persist()
context = f"Question: {question}\n{answer}"
return context
async def generate_context(self, task, qa_cache, max_retries=5):
async def generate_context(self, task, qa_cache, qa_cache_questions_vectordb, max_retries=5):
"""
Refer to the code in the voyager/agents/curriculum.py propose_next_ai_task() for implementation details.
Returns: context
@ -206,7 +206,7 @@ class DesignCurriculum(Action):
raise RuntimeError("Max retries reached, failed to propose context.")
try:
context = await self.get_context_from_task(
task=task, qa_cache=qa_cache
task=task, qa_cache=qa_cache, qa_cache_questions_vectordb=qa_cache_questions_vectordb
) # Curriculum Agent Question: How to craft 4 wooden planks in Minecraft? & Curriculum Agent Answer: ...
return context
except Exception as e:
@ -214,14 +214,15 @@ class DesignCurriculum(Action):
return await self.generate_context(
task=task,
qa_cache=qa_cache,
qa_cache_questions_vectordb=qa_cache_questions_vectordb,
max_retries=max_retries - 1,
)
async def run(self, task, qa_cache, human_msg, system_msg, *args, **kwargs):
async def run(self, task, qa_cache, qa_cache_questions_vectordb, human_msg, system_msg, *args, **kwargs):
logger.info(f"run {self.__repr__()}")
# Generate curriculum-related questions and answers.
# curriculum_qustion = await self.generate_qa_step1(events, human_msg, system_msg)
curriculum_context = await self.generate_context(task, qa_cache)
curriculum_context = await self.generate_context(task, qa_cache, qa_cache_questions_vectordb)
# Return the generated questions and answers.
return curriculum_context

View file

@ -5,8 +5,6 @@
import os
import json
from traits.trait_types import self
from metagpt.logs import logger
from metagpt.actions.minecraft.player_action import PlayerActions as Action
from metagpt.const import CKPT_DIR
@ -17,18 +15,18 @@ class RetrieveSkills(Action):
Action class for retrieving skills.
Refer to the code in the voyager/agents/skill.py for implementation details.
"""
def __init__(self, name="", context=None, llm=None):
super().__init__(name, context, llm)
self.llm.model = "gpt-3.5-turbo"
async def run(self, query, skills, *args, **kwargs):
async def run(self, query, skills, vectordb, *args, **kwargs):
# Implement the logic for retrieving skills here.
k = min(self.vectordb._collection.count(), self.retrieval_top_k)
k = min(vectordb._collection.count(), self.retrieval_top_k)
if k == 0:
return []
logger.info(f"Skill Manager retrieving for {k} skills")
docs_and_scores = self.vectordb.similarity_search_with_score(query, k=k)
docs_and_scores = vectordb.similarity_search_with_score(query, k=k)
logger.info(
f"Skill Manager retrieved skills: "
f"{', '.join([doc.metadata['name'] for doc, _ in docs_and_scores])}"
@ -44,13 +42,13 @@ class AddNewSkills(Action):
Action class for adding new skills.
Refer to the code in the voyager/agents/skill.py for implementation details.
"""
def __init__(self, name="", context=None, llm=None):
super().__init__(name, context, llm)
self.llm.model = "gpt-3.5-turbo"
async def run(
self, task, program_name, program_code, skills, skill_desp, *args, **kwargs
self, task, program_name, program_code, skills, skill_desp, vectordb, *args, **kwargs
):
# Implement the logic for adding new skills here.
# TODO: Fix this
@ -65,26 +63,27 @@ class AddNewSkills(Action):
if program_name in skills:
logger.info(f"Skill {program_name} already exists. Rewriting!")
self.vectordb._collection.delete(ids=[program_name])
vectordb._collection.delete(ids=[program_name])
i = 2
while f"{program_name}V{i}.js" in os.listdir(f"{CKPT_DIR}/skill/code"):
i += 1
dumped_program_name = f"{program_name}V{i}"
else:
dumped_program_name = program_name
self.vectordb.add_texts(
vectordb.add_texts(
texts=[skill_desp],
ids=[program_name],
metadatas=[{"name": program_name}],
)
logger.debug(f"ADD_CHECK: There are {vectordb._collection.count()} skills in vectordb")
with open(f"{CKPT_DIR}/skill/code/{dumped_program_name}.js", "w") as f:
f.write(program_code)
with open(f"{CKPT_DIR}/skill/description/{dumped_program_name}.txt", "w") as f:
f.write(skill_desp)
with open(f"{CKPT_DIR}/skill/skills.json", "w") as f:
json.dump(skills, f)
self.vectordb.persist()
vectordb.persist()
return {
"code": program_code,
"description": skill_desp,
@ -96,13 +95,13 @@ class GenerateSkillDescription(Action):
Action class for generating skill descriptions.
Refer to the code in the voyager/agents/skill.py for implementation details.
"""
def __init__(self, name="", context=None, llm=None):
super().__init__(name, context, llm)
self.llm.model = "gpt-3.5-turbo"
async def run(self, program_name, human_message, system_message, *args, **kwargs):
# Implement the logic for generating skill descriptions here.
rsp = await self._aask(prompt=human_message, system_msgs=system_message)
skill_description = f" // {rsp}"
skill_description = f" // { rsp}"
return f"async function {program_name}(bot) {{\n{skill_description}\n}}"

View file

@ -2,68 +2,14 @@
# @Date : 2023/9/23 17:06
# @Author : stellahong (stellahong@fuzhi.ai)
# @Desc :
import json
from metagpt.actions import Action
from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings
from metagpt.const import CKPT_DIR
from metagpt.config import CONFIG
class PlayerActions(Action):
def __init__(self, name="", context=None, llm=None):
super().__init__(name, context, llm)
self.skills_check = {} # for skills.json
self.qa_cache_check = {}
self.check_init = True
if (
CONFIG.resume
): # TODO: now for assert only, no update, cuz program using in step()
with open(f"{CKPT_DIR}/skill/skills.json", "r") as f:
self.skills_check = json.load(f)
with open(f"{CKPT_DIR}/curriculum/qa_cache.json", "r") as f:
self.qa_cache_check = json.load(f)
self.retrieval_top_k = 5
self.vectordb = Chroma(
collection_name="skill_vectordb",
embedding_function=OpenAIEmbeddings(),
persist_directory=f"{CKPT_DIR}/skill/vectordb",
)
self.qa_cache_questions_vectordb = Chroma(
collection_name="qa_cache_questions_vectordb",
embedding_function=OpenAIEmbeddings(),
persist_directory=f"{CKPT_DIR}/curriculum/vectordb",
)
# FIXME
if self.check_init:
# Check if Skill Manager's vectordb right using
assert self.vectordb._collection.count() >= len(self.skills_check), (
f"Skill Manager's vectordb is not synced with skills.json.\n"
f"There are {self.vectordb._collection.count()} skills in vectordb but {len(self.skills_check)} skills in skills.json.\n"
f"Did you set resume=False when initializing the manager?\n"
f"You may need to manually delete the vectordb directory for running from scratch."
)
# Check if Skill Manager's vectordb right using
assert self.qa_cache_questions_vectordb._collection.count() >= len(
self.qa_cache_check
), (
f"Curriculum Agent's qa cache question vectordb is not synced with qa_cache.json.\n"
f"There are {self.qa_cache_questions_vectordb._collection.count()} questions in vectordb "
f"but {len(self.qa_cache_check)} questions in qa_cache.json.\n"
f"Did you set resume=False when initializing the agent?\n"
f"You may need to manually delete the qa cache question vectordb directory for running from scratch.\n"
)
self.check_init = False
# TODO: change to FaissStore
# self.qa_cache_questions_vectordb = FaissStore( {CKPT_DIR}/ 'curriculum/vectordb'
"""Minecraft player info without any implementation details"""
async def run(self, *args, **kwargs):

View file

@ -31,7 +31,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
"""
游戏环境的记忆用于多个agent进行信息的共享和缓存而不需要重复在自己的角色内维护缓存
"""
event: dict[str, Any] = Field(default_factory=dict)
current_task: str = Field(default="Mine 1 wood log")
task_execution_time: float = Field(default=float)
@ -39,32 +39,32 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
default="You can mine one of oak, birch, spruce, jungle, acacia, dark oak, or mangrove logs."
)
code: str = Field(default="")
program_code: str = Field(default="") # write in skill/code/*.js
program_code: str = Field(default="") # write in skill/code/*.js
program_name: str = Field(default="")
critique: str = Field(default="")
skills: dict = Field(default_factory=dict) # for skills.json
retrieve_skills: list[str] = Field(default_factory=list)
event_summary: str = Field(default="")
qa_cache: dict[str, str] = Field(default_factory=dict)
completed_tasks: list[str] = Field(default_factory=list) # Critique things
failed_tasks: list[str] = Field(default_factory=list)
skill_desp: str = Field(default="")
chest_memory: dict[str, Any] = Field(
default_factory=dict
) # eg: {'(1344, 64, 1381)': 'Unknown'}
chest_observation: str = Field(default="") # eg: "Chests: None\n\n"
mf_instance: MineflayerEnv = Field(default_factory=MineflayerEnv)
runtime_status: bool = False # equal to action execution status: success or failed
@property
def progress(self):
# return len(self.completed_tasks) + 10 # Test only
return len(self.completed_tasks)
@property
def programs(self):
programs = ""
@ -75,25 +75,41 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
for primitives in load_skills_code():
programs += f"{primitives}\n\n"
return programs
@property
def warm_up(self):
return self.mf_instance.warm_up
@property
def core_inv_items_regex(self):
return self.mf_instance.core_inv_items_regex
@property
def qa_cache_questions_vectordb(self):
return Chroma(
collection_name="qa_cache_questions_vectordb",
embedding_function=OpenAIEmbeddings(),
persist_directory=f"{CKPT_DIR}/curriculum/vectordb",
)
@property
def vectordb(self):
return Chroma(
collection_name="skill_vectordb",
embedding_function=OpenAIEmbeddings(),
persist_directory=f"{CKPT_DIR}/skill/vectordb",
)
def set_mc_port(self, mc_port):
self.mf_instance.set_mc_port(mc_port)
self.set_mc_resume()
def set_mc_resume(self):
if CONFIG.resume:
logger.info(f"Loading Action Developer from {CKPT_DIR}/action")
with open(f"{CKPT_DIR}/action/chest_memory.json", "r") as f:
self.chest_memory = json.load(f)
logger.info(f"Loading Curriculum Agent from {CKPT_DIR}/curriculum")
with open(f"{CKPT_DIR}/curriculum/completed_tasks.json", "r") as f:
self.completed_tasks = json.load(f)
@ -103,25 +119,72 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
logger.info(f"Loading Skill Manager from {CKPT_DIR}/skill\033[0m")
with open(f"{CKPT_DIR}/skill/skills.json", "r") as f:
self.skills = json.load(f)
logger.info(f"Loading Qa Cache from {CKPT_DIR}/curriculum\033[0m")
with open(f"{CKPT_DIR}/curriculum/qa_cache.json", "r") as f:
self.qa_cache = json.load(f)
self.qa_cache = json.load(f)
if self.vectordb._collection.count() == 0:
# Set vdvs for skills & qa_cache
skill_desps = [
skill["description"] for program_name, skill in self.skills.items()
]
program_names = [
program_name for program_name, skill in self.skills.items()
]
metadatas = [{"name": program_name} for program_name in program_names]
# add vectordb from file
ids = self.vectordb.add_texts(
texts=skill_desps,
ids=program_names,
metadatas=metadatas,
)
self.vectordb.persist()
if self.qa_cache_questions_vectordb._collection.count() == 0:
questions = [question for question, answer in self.qa_cache.items()]
self.qa_cache_questions_vectordb.add_texts(texts=questions)
self.qa_cache_questions_vectordb.persist()
logger.info(
f"INIT_CHECK: There are {self.vectordb._collection.count()} skills in vectordb and {len(self.skills)} skills in skills.json."
)
# Check if Skill Manager's vectordb right using
assert self.vectordb._collection.count() >= len(self.skills), (
f"Skill Manager's vectordb is not synced with skills.json.\n"
f"There are {self.vectordb._collection.count()} skills in vectordb but {len(self.skills)} skills in skills.json.\n"
f"Did you set resume=False when initializing the manager?\n"
f"You may need to manually delete the vectordb directory for running from scratch."
)
logger.info(
f"INIT_CHECK: There are {self.qa_cache_questions_vectordb._collection.count()} qa_cache in vectordb and {len(self.qa_cache)} questions in qa_cache.json."
)
assert self.qa_cache_questions_vectordb._collection.count() >= len(
self.qa_cache
), (
f"Curriculum Agent's qa cache question vectordb is not synced with qa_cache.json.\n"
f"There are {self.qa_cache_questions_vectordb._collection.count()} questions in vectordb "
f"but {len(self.qa_cache)} questions in qa_cache.json.\n"
f"Did you set resume=False when initializing the agent?\n"
f"You may need to manually delete the qa cache question vectordb directory for running from scratch.\n"
)
def register_roles(self, roles: Iterable[Minecraft]):
for role in roles:
role.set_memory(self)
def update_event(self, event: Dict):
if self.event == event:
return
self.event = event
# self.update_chest_memory(event)
# self.event_summary = self.summarize_chatlog(event)
def update_task(self, task: str):
self.current_task = task
def update_context(self, context: str):
self.context = context
@ -130,22 +193,22 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
def update_code(self, code: str):
self.code = code # action_developer.gen_action_code to HERE
def update_program_name(self, program_name: str):
self.program_name = program_name
def update_critique(self, critique: str):
self.critique = critique # critic_agent.check_task_success to HERE
def append_skill(self, skill: dict):
self.skills[self.program_name] = skill # skill_manager.retrieve_skills to HERE
def update_retrieve_skills(self, retrieve_skills: list):
self.retrieve_skills = retrieve_skills
def update_skill_desp(self, skill_desp: str):
self.skill_desp = skill_desp
def update_chest_memory(self, events: Dict):
"""
Input: events: Dict
@ -165,13 +228,13 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
self.chest_memory[position] = chest
with open(f"{CKPT_DIR}/action/chest_memory.json", "w") as f:
json.dump(self.chest_memory, f)
def update_chest_observation(self):
"""
update chest_memory to chest_observation.
Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/action.py
"""
chests = []
for chest_position, chest in self.chest_memory.items():
if isinstance(chest, dict) and len(chest) > 0:
@ -189,7 +252,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
self.chest_observation = f"Chests:\n{chests}\n\n"
else:
self.chest_observation = f"Chests: None\n\n"
def summarize_chatlog(self, events):
def filter_item(message: str):
craft_pattern = r"I cannot make \w+ because I need: (.*)"
@ -198,25 +261,28 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
)
mine_pattern = r"I need at least a (.*) to mine \w+!"
if re.match(craft_pattern, message):
self.event_summary = re.match(craft_pattern, message).groups()[0]
self.event_summary = re.match(craft_pattern, message).groups()[0]
elif re.match(craft_pattern2, message):
self.event_summary = "a nearby crafting table"
elif re.match(mine_pattern, message):
self.event_summary = re.match(mine_pattern, message).groups()[0]
else:
self.event_summary = ""
chatlog = set()
for event_type, event in events:
if event_type == "onChat":
item = filter_item(event["onChat"])
if item:
chatlog.add(item)
self.event_summary = "I also need " + ", ".join(chatlog) + "." if chatlog else ""
self.event_summary = (
"I also need " + ", ".join(chatlog) + "." if chatlog else ""
)
def reset_block_info(self):
# revert all the placing event in the last step
pass
def update_exploration_progress(self, success: bool):
"""
Split task into completed_tasks or failed_tasks
@ -252,9 +318,9 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
)
self.event[-1][1]["inventory"] = new_events[-1][1]["inventory"]
self.event[-1][1]["voxels"] = new_events[-1][1]["voxels"]
self.save_sorted_tasks()
def save_sorted_tasks(self):
updated_completed_tasks = []
# record repeated failed tasks
@ -263,21 +329,21 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
for task in self.completed_tasks:
if task not in updated_completed_tasks:
updated_completed_tasks.append(task)
# remove completed tasks from failed tasks
for task in updated_completed_tasks:
while task in updated_failed_tasks:
updated_failed_tasks.remove(task)
self.completed_tasks = updated_completed_tasks
self.failed_tasks = updated_failed_tasks
# dump to json
with open(f"{CKPT_DIR}/curriculum/completed_tasks.json", "w") as f:
json.dump(self.completed_tasks, f)
with open(f"{CKPT_DIR}/curriculum/failed_tasks.json", "w") as f:
json.dump(self.failed_tasks, f)
async def on_event_retrieve(self, *args):
"""
Retrieve Minecraft events.
@ -295,9 +361,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
"wait_ticks": 20,
}
)
difficulty = (
"easy" if len(self.completed_tasks) > 15 else "peaceful"
)
difficulty = "easy" if len(self.completed_tasks) > 15 else "peaceful"
events = self.mf_instance.step(
"bot.chat(`/time set ${getNextTime()}`);\n"
+ f"bot.chat('/difficulty {difficulty}');"
@ -318,7 +382,8 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
)
self.update_event(events)
logger.error(f"Failed to retrieve Minecraft events: {str(e)}")
return events
async def on_event_execute(self, *args):
"""
Execute Minecraft events.
@ -334,7 +399,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
"""
try:
events = self.mf_instance.step(
code = self.code,
code=self.code,
programs=self.programs,
)
self.update_event(events)
@ -353,6 +418,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
)
self.update_event(events)
logger.error(f"Failed to execute Minecraft events: {str(e)}")
return events
class MinecraftPlayer(SoftwareCompany):
@ -360,16 +426,16 @@ class MinecraftPlayer(SoftwareCompany):
Software Company: Possesses a team, SOP (Standard Operating Procedures), and a platform for instant messaging,
dedicated to writing executable code.
"""
environment: Environment = Field(default_factory=Environment)
game_memory: GameEnvironment = Field(default_factory=GameEnvironment)
investment: float = Field(default=50.0)
task: str = Field(default="")
game_info: dict = Field(default={})
def set_port(self, mc_port):
self.game_memory.set_mc_port(mc_port)
def check_complete_round(self):
complete_round = []
for role in self.environment.roles.values():
@ -381,7 +447,7 @@ class MinecraftPlayer(SoftwareCompany):
complete_round_tag = all(complete_round)
logger.info(f"complete_round {complete_round}")
return complete_round_tag
def update_round(self):
for role in self.environment.roles.values():
role.finish_step = False
@ -389,11 +455,11 @@ class MinecraftPlayer(SoftwareCompany):
role._rc.todo = None
role.finish_state = len(role._actions)
logger.info(f"round_id:{role.round_id}")
def hire(self, roles: list[Role]):
self.environment.add_roles(roles)
self.game_memory.register_roles(roles)
def start(self, task, round=0):
"""Start a project from publishing boss requirement."""
self.task = task
@ -401,14 +467,14 @@ class MinecraftPlayer(SoftwareCompany):
Message(role="Player", content=task, cause_by=PlayerActions, round_id=round)
)
logger.info(self.game_info)
def _save(self):
logger.info(self.json())
def _reset(self):
for role_profile, role in self.environment.roles.items():
role.reset_state()
async def run(self, n_round=3):
"""Run company until target round or no money"""
round_id = 0
@ -434,18 +500,17 @@ class MinecraftPlayer(SoftwareCompany):
programs="",
)
self.game_memory.update_event(events)
while n_round > 0:
# self._save()
if self.check_complete_round():
n_round -= 1
self.update_round()
round_id += 1
# add new task into env and continue
# fixme: update self.task
self.start(task=self.task, round=round_id)
logger.info(f"{n_round=}")
self._check_balance()
await self.environment.run()

View file

@ -300,6 +300,7 @@ class CurriculumDesigner(Base):
inventoryUsed = events[-1][1]["status"]["inventoryUsed"]
task = self.game_memory.current_task
qa_cache = self.game_memory.qa_cache
qa_cache_questions_vectordb = self.game_memory.qa_cache_questions_vectordb
if self.game_memory.progress == 0:
context = self.game_memory.context
@ -309,7 +310,7 @@ class CurriculumDesigner(Base):
)
else:
context = await DesignCurriculum().run(
task, qa_cache, human_msg, system_msg, *args, **kwargs
task, qa_cache, qa_cache_questions_vectordb, human_msg, system_msg, *args, **kwargs
)
self.perform_game_info_callback(context, self.game_memory.update_context)
return Message(

View file

@ -19,40 +19,42 @@ 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])
# 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)
vectordb = self.game_memory.vectordb
retrieve_skills = await RetrieveSkills().run(query, skills, vectordb)
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)
@ -62,20 +64,21 @@ 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
vectordb = self.game_memory.vectordb
new_skills_info = await AddNewSkills().run(
task, program_name, program_code, skills, skill_desp
task, program_name, program_code, skills, skill_desp, vectordb
)
self.perform_game_info_callback(new_skills_info, self.game_memory.append_skill)
return Message(
@ -83,13 +86,13 @@ 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)
# 获取最新的游戏周边信息
context = self.game_memory.context
task = self.game_memory.current_task
@ -97,27 +100,27 @@ class SkillManager(Base):
self.perform_game_info_callback(self.game_memory.event, self.game_memory.summarize_chatlog)
event_summary = self.game_memory.event_summary
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,
@ -136,10 +139,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)}")