Fix story maker bug
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
instance_id = "fairy_tale_writer"
|
||||
fullname = "tracy wang"
|
||||
llm_model_name = "gpt-3.5-turbo-16k-0613"
|
||||
enable_function = []
|
||||
|
||||
[[prompt]]
|
||||
role = "system"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
instance_id = "agent:xxxxxxabcde"
|
||||
fullname = "musk"
|
||||
enable_function = []
|
||||
|
||||
[[prompt]]
|
||||
role = "system"
|
||||
content = "你有丰富的管理技能,擅长将复杂工作拆解成简单的任务,让团队成员高效协作。"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
instance_id = "studio_director"
|
||||
fullname = "tracy wang"
|
||||
llm_model_name = "gpt-3.5-turbo-16k-0613"
|
||||
enable_function = ["text_to_speech"]
|
||||
|
||||
[[prompt]]
|
||||
role = "system"
|
||||
content = "你是一个演播导演,请将下面故事改编成朗读剧本,提取旁白和角色台词,每个角色需要有性别、年龄、以及每句台词的语气。并调用text_to_speech function生成音频数据。"
|
||||
content = "你是一个故事播音员,请将下面故事改编成播音剧本,提取旁白和角色台词,以及每个角色需要有性别、年龄、以及每句台词的语气,最后生成音频文件。"
|
||||
|
||||
@@ -8,10 +8,12 @@ name = "story_maker"
|
||||
name = "manager"
|
||||
fullname = "总导演"
|
||||
agent="manager"
|
||||
enable_function = []
|
||||
|
||||
[[roles.manager.prompt]]
|
||||
role="system"
|
||||
content="""
|
||||
你是一个语音故事制作总导演,与客户对接并向团队下达指令。你的团队分为下面几个成员:writer,studio_director。一个故事制作分成两个阶段:让writer写出故事,再交由studio_director演播故事。你的基本工作模式是:
|
||||
你是一个语音故事制作总导演,与客户对接并向团队下达指令。你的团队分为下面几个成员:writer,studio_director。一个故事制作分成两个阶段:让writer写出故事,再交由studio_director演播故事生成音频文件。你的基本工作模式是:
|
||||
1. 收到客户的明确的指令后,让writer写出故事
|
||||
2. 将writer写出的故事交给studio_director演播
|
||||
3. 当你决定要和成员通信时,请使用下面形式输出需要通信的消息
|
||||
@@ -25,6 +27,7 @@ content="""
|
||||
name = "writer"
|
||||
agent = "fairy_tale_writer"
|
||||
fullname = "作家"
|
||||
enable_function = []
|
||||
[[roles.writer.prompt]]
|
||||
role="system"
|
||||
content=""
|
||||
@@ -32,6 +35,7 @@ content=""
|
||||
[roles.studio_director]
|
||||
name = "studio_director"
|
||||
agent = "studio_director"
|
||||
enable_function = ["text_to_speech"]
|
||||
[[roles.studio_director.prompt]]
|
||||
role="system"
|
||||
content=""
|
||||
|
||||
+40
-38
@@ -26,7 +26,7 @@ class AgentPrompt:
|
||||
self.system_message = None
|
||||
|
||||
def as_str(self)->str:
|
||||
result_str = ""
|
||||
result_str = ""
|
||||
if self.system_message:
|
||||
result_str += self.system_message.get("role") + ":" + self.system_message.get("content") + "\n"
|
||||
if self.messages:
|
||||
@@ -34,18 +34,18 @@ class AgentPrompt:
|
||||
result_str += msg.get("role") + ":" + msg.get("content") + "\n"
|
||||
|
||||
return result_str
|
||||
|
||||
|
||||
def to_message_list(self):
|
||||
result = []
|
||||
if self.system_message:
|
||||
result.append(self.system_message)
|
||||
result.extend(self.messages)
|
||||
return result
|
||||
|
||||
|
||||
def append(self,prompt):
|
||||
if prompt is None:
|
||||
return
|
||||
|
||||
|
||||
if prompt.system_message is not None:
|
||||
if self.system_message is None:
|
||||
self.system_message = prompt.system_message
|
||||
@@ -99,9 +99,9 @@ class AIAgentTemplete:
|
||||
logger.error("load prompt from config failed!")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
class AIAgent:
|
||||
def __init__(self) -> None:
|
||||
@@ -111,7 +111,7 @@ class AIAgent:
|
||||
self.agent_id:str = None
|
||||
self.template_id:str = None
|
||||
self.fullname:str = None
|
||||
self.powerby = None
|
||||
self.powerby = None
|
||||
self.enable = True
|
||||
self.enable_kb = False
|
||||
self.enable_timestamp = False
|
||||
@@ -124,7 +124,7 @@ class AIAgent:
|
||||
self.owner_env : Environment = None
|
||||
self.owenr_bus = None
|
||||
self.enable_function_list = []
|
||||
|
||||
|
||||
@classmethod
|
||||
def create_from_templete(cls,templete:AIAgentTemplete, fullname:str):
|
||||
# Agent just inherit from templete on craete,if template changed,agent will not change
|
||||
@@ -137,7 +137,7 @@ class AIAgent:
|
||||
result_agent.powerby = templete.author
|
||||
result_agent.prompt = templete.prompt
|
||||
return result_agent
|
||||
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
if config.get("instance_id") is None:
|
||||
logger.error("agent instance_id is None!")
|
||||
@@ -188,7 +188,7 @@ class AIAgent:
|
||||
if llm_result_str == "ignore":
|
||||
r.state = "ignore"
|
||||
return r
|
||||
|
||||
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
|
||||
@@ -205,7 +205,7 @@ class AIAgent:
|
||||
|
||||
r.send_msgs.append(new_msg)
|
||||
is_need_wait = True
|
||||
|
||||
|
||||
case "post_msg":# postmsg($target_id,$msg_content)
|
||||
if len(func_args) != 1:
|
||||
logger.error(f"parse postmsg failed! {func_call}")
|
||||
@@ -215,22 +215,22 @@ class AIAgent:
|
||||
msg_content = func_item.body
|
||||
new_msg.set(self.agent_id,target_id,msg_content)
|
||||
r.post_msgs.append(new_msg)
|
||||
|
||||
|
||||
case "call":# call($func_name,$args_str)
|
||||
r.calls.append(func_item)
|
||||
is_need_wait = True
|
||||
return True
|
||||
case "post_call": # post_call($func_name,$args_str)
|
||||
r.post_calls.append(func_item)
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
current_func : FunctionItem = None
|
||||
for line in lines:
|
||||
if line.startswith("##/"):
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
|
||||
|
||||
func_name,func_args = AgentMsg.parse_function_call(line[3:])
|
||||
current_func = FunctionItem(func_name,func_args)
|
||||
else:
|
||||
@@ -238,11 +238,11 @@ class AIAgent:
|
||||
current_func.append_body(line + "\n")
|
||||
else:
|
||||
r.resp += line + "\n"
|
||||
|
||||
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
|
||||
|
||||
if len(r.send_msgs) > 0 or len(r.calls) > 0:
|
||||
r.state = "waiting"
|
||||
else:
|
||||
@@ -279,21 +279,22 @@ class AIAgent:
|
||||
def _get_inner_functions(self) -> dict:
|
||||
if self.owner_env is None:
|
||||
return None
|
||||
|
||||
|
||||
all_inner_function = self.owner_env.get_all_ai_functions()
|
||||
if all_inner_function is None:
|
||||
return None
|
||||
|
||||
|
||||
result_func = []
|
||||
result_len = 0
|
||||
for inner_func in all_inner_function:
|
||||
func_name = inner_func.get_name()
|
||||
if self.enable_function_list:
|
||||
if self.enable_function_list is not None:
|
||||
if len(self.enable_function_list) > 0:
|
||||
if func_name not in self.enable_function_list:
|
||||
logger.debug(f"ageint {self.agent_id} ignore inner func:{func_name}")
|
||||
continue
|
||||
|
||||
else:
|
||||
continue
|
||||
this_func = {}
|
||||
this_func["name"] = func_name
|
||||
this_func["description"] = inner_func.get_description()
|
||||
@@ -313,28 +314,29 @@ class AIAgent:
|
||||
func_node : AIFunction = self.owner_env.get_ai_function(func_name)
|
||||
if func_node is None:
|
||||
return "execute failed,function not found"
|
||||
|
||||
|
||||
ineternal_call_record = AgentMsg.create_internal_call_msg(func_name,arguments,org_msg.get_msg_id(),org_msg.target)
|
||||
try:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
except Exception as e:
|
||||
result_str = "call error:" + str(e)
|
||||
result_str = "call error:" + str(e)
|
||||
logger.error(f"llm execute inner func:{func_name} error:{e}")
|
||||
|
||||
|
||||
|
||||
logger.info("llm execute inner func result:" + result_str)
|
||||
inner_functions,inner_function_len = self._get_inner_functions()
|
||||
prompt.messages.append({"role":"function","content":result_str,"name":func_name})
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
|
||||
|
||||
|
||||
ineternal_call_record.result_str = task_result.result_str
|
||||
ineternal_call_record.done_time = time.time()
|
||||
org_msg.inner_call_chain.append(ineternal_call_record)
|
||||
|
||||
if stack_limit > 0:
|
||||
inner_func_call_node = task_result.result_message.get("function_call")
|
||||
|
||||
|
||||
if inner_func_call_node:
|
||||
return await self._execute_func(inner_func_call_node,prompt,org_msg,stack_limit-1)
|
||||
return await self._execute_func(inner_func_call_node,prompt,org_msg,stack_limit-1)
|
||||
else:
|
||||
return task_result.result_str
|
||||
|
||||
@@ -344,7 +346,7 @@ class AIAgent:
|
||||
def _format_msg_by_env_value(self,prompt:AgentPrompt):
|
||||
if self.owner_env is None:
|
||||
return
|
||||
|
||||
|
||||
for msg in prompt.messages:
|
||||
old_content = msg.get("content")
|
||||
msg["content"] = old_content.format_map(self.owner_env)
|
||||
@@ -380,7 +382,7 @@ class AIAgent:
|
||||
|
||||
system_prompt_len = prompt.get_prompt_token_len()
|
||||
input_len = len(msg.body)
|
||||
|
||||
|
||||
history_prmpt,history_token_len = await self._get_prompt_from_session(chatsession,system_prompt_len + function_token_len,input_len)
|
||||
prompt.append(history_prmpt) # chat context
|
||||
|
||||
@@ -397,7 +399,7 @@ class AIAgent:
|
||||
if inner_func_call_node:
|
||||
#TODO to save more token ,can i use msg_prompt?
|
||||
final_result = await self._execute_func(inner_func_call_node,prompt,msg)
|
||||
|
||||
|
||||
llm_result : LLMResult = self._get_llm_result_type(final_result)
|
||||
is_ignore = False
|
||||
result_prompt_str = ""
|
||||
@@ -415,21 +417,21 @@ class AIAgent:
|
||||
agent_sesion = AIChatSession.get_session(self.agent_id,f"{sendmsg.target}#{sendmsg.topic}",self.chat_db)
|
||||
agent_sesion.append(sendmsg)
|
||||
agent_sesion.append(send_resp)
|
||||
|
||||
|
||||
final_result = llm_result.resp + result_prompt_str
|
||||
|
||||
if is_ignore is not True:
|
||||
resp_msg = msg.create_resp_msg(final_result)
|
||||
chatsession.append(msg)
|
||||
chatsession.append(resp_msg)
|
||||
|
||||
|
||||
return resp_msg
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_id(self) -> str:
|
||||
return self.agent_id
|
||||
|
||||
|
||||
def get_fullname(self) -> str:
|
||||
return self.fullname
|
||||
|
||||
@@ -438,14 +440,14 @@ class AIAgent:
|
||||
|
||||
def get_llm_model_name(self) -> str:
|
||||
return self.llm_model_name
|
||||
|
||||
|
||||
def get_max_token_size(self) -> int:
|
||||
return self.max_token_size
|
||||
|
||||
|
||||
async def _get_prompt_from_session(self,chatsession:AIChatSession,system_token_len,input_token_len,is_groupchat=False) -> AgentPrompt:
|
||||
# TODO: get prompt from group chat is different from single chat
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len - input_token_len
|
||||
messages = chatsession.read_history() # read
|
||||
messages = chatsession.read_history() # read
|
||||
result_token_len = 0
|
||||
result_prompt = AgentPrompt()
|
||||
read_history_msg = 0
|
||||
|
||||
+23
-21
@@ -19,14 +19,14 @@ class AIBusHandler:
|
||||
async def handle_message(self,msg:AgentMsg) -> Any:
|
||||
if self.handler is None:
|
||||
return None
|
||||
|
||||
|
||||
resp_msg = await self.handler(msg)
|
||||
if self.enable_defualt_proc:
|
||||
if resp_msg is not None:
|
||||
await self.owner_bus.post_message(resp_msg,False)
|
||||
|
||||
return resp_msg
|
||||
|
||||
|
||||
class AIBus:
|
||||
_instance = None
|
||||
@classmethod
|
||||
@@ -48,16 +48,16 @@ class AIBus:
|
||||
if msg.rely_msg_id is not None:
|
||||
handler.results[msg.rely_msg_id] = msg
|
||||
return None
|
||||
|
||||
|
||||
handler.queue.put_nowait(msg)
|
||||
self.start_process(target_id)
|
||||
return True
|
||||
|
||||
|
||||
if use_unhandle:
|
||||
if self.unhandle_handler is not None:
|
||||
if await self.unhandle_handler(self,msg):
|
||||
return await self.post_message(msg,False)
|
||||
|
||||
|
||||
logger.warn(f"post message to {msg.target} failed!,target not found")
|
||||
return False
|
||||
|
||||
@@ -71,7 +71,7 @@ class AIBus:
|
||||
if sender_handler is None:
|
||||
logger.warn(f"sender {sender_id} not register on AI_BUS!")
|
||||
return None
|
||||
|
||||
|
||||
post_result = await self.post_message(msg)
|
||||
if post_result is False:
|
||||
return None
|
||||
@@ -84,37 +84,39 @@ class AIBus:
|
||||
msg.status = AgentMsgStatus.RESPONSED
|
||||
del sender_handler.results[msg.msg_id]
|
||||
return resp
|
||||
|
||||
|
||||
await asyncio.sleep(0.2)
|
||||
retry_times += 1
|
||||
if retry_times > 5*120: # default timeout is 120 sec
|
||||
if retry_times > 5*240: # default timeout is 240 sec
|
||||
msg.status = AgentMsgStatus.ERROR
|
||||
return None
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def register_unhandle_message_handler(self,handler:Any) -> Queue:
|
||||
self.unhandle_handler = handler
|
||||
|
||||
# means sub
|
||||
def register_message_handler(self,handler_name:str,handler:Any) -> Queue:
|
||||
handler_node = AIBusHandler(handler,self)
|
||||
def register_message_handler(self,handler_name:str,handler:Any) -> Queue:
|
||||
handler_node = AIBusHandler(handler,self)
|
||||
self.handlers[handler_name] = handler_node
|
||||
return handler_node.queue
|
||||
|
||||
|
||||
async def process_queue(self, handler:AIBusHandler):
|
||||
while True:
|
||||
# Wait for a message
|
||||
message = await handler.queue.get()
|
||||
|
||||
#try:
|
||||
try:
|
||||
# Try to handle the message
|
||||
await handler.handle_message(message)
|
||||
#except Exception as e:
|
||||
await handler.handle_message(message)
|
||||
except Exception as e:
|
||||
# If an error occurs, put the message back into the queue
|
||||
# logger.error(f"handle message {message.msg_id} failed! {e}")
|
||||
logger.error(f"handle message {message.msg_id} failed! {e}")
|
||||
logger.exception(e)
|
||||
raise e
|
||||
#self.queues[name].put_nowait(message)
|
||||
|
||||
|
||||
return
|
||||
|
||||
def start_process(self,target_name):
|
||||
@@ -122,12 +124,12 @@ class AIBus:
|
||||
if handler is None:
|
||||
logger.error(f"handler {target_name} not found!")
|
||||
return
|
||||
|
||||
|
||||
if handler.handler is None:
|
||||
return
|
||||
|
||||
if handler.working_task is not None:
|
||||
logger.warn(f"handler {target_name} is already working!")
|
||||
return
|
||||
|
||||
handler.working_task = asyncio.create_task(self.process_queue(handler))
|
||||
|
||||
handler.working_task = asyncio.create_task(self.process_queue(handler))
|
||||
|
||||
@@ -118,7 +118,7 @@ class ComputeKernel:
|
||||
if task_req.state == ComputeTaskState.ERROR:
|
||||
break
|
||||
|
||||
if check_times >= 20:
|
||||
if check_times >= 120:
|
||||
task_req.state = ComputeTaskState.ERROR
|
||||
break
|
||||
|
||||
@@ -129,7 +129,7 @@ class ComputeKernel:
|
||||
if task_req.state == ComputeTaskState.DONE:
|
||||
return task_req.result
|
||||
|
||||
return "error!"
|
||||
raise Exception("error!")
|
||||
|
||||
|
||||
def text_embedding(self,input:str,model_name:Optional[str] = None):
|
||||
|
||||
@@ -20,7 +20,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
if cls._instance is None:
|
||||
cls._instance = OpenAI_ComputeNode()
|
||||
return cls._instance
|
||||
|
||||
|
||||
@classmethod
|
||||
def declare_user_config(cls):
|
||||
if os.getenv("OPENAI_API_KEY_") is None:
|
||||
@@ -46,7 +46,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
if self.openai_api_key is None:
|
||||
logger.error("openai_api_key is None!")
|
||||
return False
|
||||
|
||||
|
||||
openai.api_key = self.openai_api_key
|
||||
self.start()
|
||||
return True
|
||||
@@ -68,7 +68,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
|
||||
resp = openai.Embedding.create(model=model_name,
|
||||
input=input)
|
||||
|
||||
|
||||
# resp = {
|
||||
# "object": "list",
|
||||
# "data": [
|
||||
@@ -86,7 +86,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
|
||||
logger.info(f"openai response: {resp}")
|
||||
|
||||
result = ComputeTaskResult()
|
||||
result = ComputeTaskResult()
|
||||
result.set_from_task(task)
|
||||
result.worker_id = self.node_id
|
||||
result.result = resp["data"][0]["embedding"]
|
||||
@@ -100,23 +100,23 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
if max_token_size is None:
|
||||
max_token_size = 4000
|
||||
|
||||
result_token = int(max_token_size * 0.4)
|
||||
|
||||
logger.info(f"call openai {mode_name} prompts: {prompts}")
|
||||
result_token = max_token_size
|
||||
|
||||
if llm_inner_functions is None:
|
||||
logger.info(f"call openai {mode_name} prompts: {prompts}")
|
||||
resp = openai.ChatCompletion.create(model=mode_name,
|
||||
messages=prompts,
|
||||
max_tokens=result_token,
|
||||
temperature=0.7)
|
||||
else:
|
||||
logger.info(f"call openai {mode_name} prompts: {prompts} functions: {json.dumps(llm_inner_functions)}")
|
||||
resp = openai.ChatCompletion.create(model=mode_name,
|
||||
messages=prompts,
|
||||
functions=llm_inner_functions,
|
||||
max_tokens=result_token,
|
||||
temperature=0.7) # TODO: add temperature to task params?
|
||||
|
||||
|
||||
|
||||
logger.info(f"openai response: {json.dumps(resp, indent=4)}")
|
||||
|
||||
result = ComputeTaskResult()
|
||||
@@ -139,6 +139,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
result.result_message = resp["choices"][0]["message"]
|
||||
if token_usage:
|
||||
result.result_refers["token_usage"] = token_usage
|
||||
logger.info(f"openai success response: {result.result_str}")
|
||||
return result
|
||||
case _:
|
||||
task.state = ComputeTaskState.ERROR
|
||||
@@ -148,7 +149,7 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
if self.is_start is True:
|
||||
return
|
||||
self.is_start = True
|
||||
|
||||
|
||||
async def _run_task_loop():
|
||||
while True:
|
||||
task = await self.task_queue.get()
|
||||
@@ -171,13 +172,13 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
|
||||
|
||||
def is_support(self, task: ComputeTask) -> bool:
|
||||
if task.task_type == ComputeTaskType.LLM_COMPLETION:
|
||||
if task.task_type == ComputeTaskType.LLM_COMPLETION:
|
||||
if not task.params["model_name"]:
|
||||
return True
|
||||
model_name : str = task.params["model_name"]
|
||||
if model_name.startswith("gpt-"):
|
||||
return True
|
||||
|
||||
|
||||
if task.task_type == ComputeTaskType.TEXT_EMBEDDING:
|
||||
if task.params["model_name"] == "text-embedding-ada-002":
|
||||
return True
|
||||
|
||||
@@ -83,9 +83,9 @@ class TextToSpeechFunction(AIFunction):
|
||||
continue
|
||||
|
||||
if audio is not None:
|
||||
path = os.path.join(os.curdir, "{}.mp3".format(random.sample('zyxwvutsrqponmlkjihgfedcba', 10)))
|
||||
path = os.path.join(os.path.realpath(os.curdir), "{}.mp3".format(''.join(random.sample('zyxwvutsrqponmlkjihgfedcba', 10))))
|
||||
audio.export(path, format="mp3")
|
||||
return "complete.file path:{}".format(path)
|
||||
return "已经生成音频文件, 文件路径为{}".format(path)
|
||||
else:
|
||||
return "failed"
|
||||
|
||||
|
||||
+58
-56
@@ -2,7 +2,7 @@ import logging
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import time
|
||||
from asyncio import Queue
|
||||
from typing import Optional,Tuple,List
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -32,7 +32,7 @@ class MessageFilter:
|
||||
|
||||
# TODO: add more filter
|
||||
return None
|
||||
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
self.filters = config
|
||||
return True
|
||||
@@ -68,8 +68,8 @@ class Workflow:
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
if config is None:
|
||||
return False
|
||||
|
||||
if config.get("name") is None:
|
||||
|
||||
if config.get("name") is None:
|
||||
logger.error("workflow config must have name")
|
||||
return False
|
||||
self.workflow_name = config.get("name")
|
||||
@@ -84,7 +84,7 @@ class Workflow:
|
||||
if self.rule_prompt.load_from_config(config.get("prompt")) is False:
|
||||
logger.error("Workflow load prompt failed")
|
||||
return False
|
||||
|
||||
|
||||
if config.get("roles") is None:
|
||||
logger.error("workflow config must have roles")
|
||||
return False
|
||||
@@ -106,13 +106,13 @@ class Workflow:
|
||||
self.env_db_file = self.owner_workflow.env_db_file
|
||||
self.workflow_env = WorkflowEnvironment(self.workflow_id,self.env_db_file)
|
||||
|
||||
env_ndoe = config.get("enviroment")
|
||||
env_ndoe = config.get("enviroment")
|
||||
if env_ndoe is not None:
|
||||
if self._load_env_from_config(env_ndoe) is False:
|
||||
logger.error("Workflow load env failed")
|
||||
return False
|
||||
|
||||
connected_env_ndoe = config.get("connected_env")
|
||||
connected_env_ndoe = config.get("connected_env")
|
||||
if connected_env_ndoe is not None:
|
||||
for _node in connected_env_ndoe:
|
||||
env_id = _node.get("env_id")
|
||||
@@ -124,13 +124,13 @@ class Workflow:
|
||||
logger.error(f"Workflow load connected_env failed, env {env_id} not found!")
|
||||
return False
|
||||
self.connect_to_environment(remote_env,_node.get("event2msg"))
|
||||
|
||||
|
||||
sub_workflows = config.get("sub_workflows")
|
||||
if sub_workflows is not None:
|
||||
if self._load_sub_workflows(sub_workflows) is False:
|
||||
logger.error("Workflow load sub workflows failed")
|
||||
return False
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def _load_env_from_config(self,config:dict) -> bool:
|
||||
@@ -147,7 +147,7 @@ class Workflow:
|
||||
return False
|
||||
self.sub_workflows[k] = sub_workflow
|
||||
return True
|
||||
|
||||
|
||||
def _parse_msg_target(self,s:str)->list[str]:
|
||||
return s.split(".")
|
||||
|
||||
@@ -170,12 +170,12 @@ class Workflow:
|
||||
if current_workflow is None:
|
||||
logger.error(f"sub workflow {inner_obj_id[i]} not found!")
|
||||
return None
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
|
||||
logger.error(f"{msg.target} not found! forword message failed!")
|
||||
return None
|
||||
|
||||
|
||||
def get_workflow_id_from_target(self,target:str) -> str:
|
||||
target_list = target.split(".")
|
||||
if len(target_list) == 0:
|
||||
@@ -203,11 +203,11 @@ class Workflow:
|
||||
|
||||
#1. workflow start process message
|
||||
final_result = None
|
||||
|
||||
|
||||
# this is workflow's group_chat session
|
||||
session_topic = msg.sender + "#" + msg.topic
|
||||
chatsesssion = AIChatSession.get_session(self.workflow_id,session_topic,self.db_file)
|
||||
|
||||
|
||||
#2. find role by msg.mentions or workflow's selector logic
|
||||
if msg.mentions is not None:
|
||||
if not self.workflow_id in msg.mentions:
|
||||
@@ -219,20 +219,20 @@ class Workflow:
|
||||
this_role = self.role_group.get(mention)
|
||||
if this_role is not None:
|
||||
return await self.role_process_msg(msg,this_role,chatsesssion)
|
||||
|
||||
|
||||
if self.input_filter is not None:
|
||||
select_role_id = self.input_filter.select(msg)
|
||||
if select_role_id is not None:
|
||||
if select_role_id is not None:
|
||||
select_role = self.role_group.get(select_role_id)
|
||||
if select_role is None:
|
||||
logger.error(f"input_filter return invalid role id:{select_role_id}, role not found in role_group")
|
||||
return None
|
||||
|
||||
|
||||
return await self.role_process_msg(msg,select_role,chatsesssion)
|
||||
else:
|
||||
logger.error(f"input_filter return None for :{msg.body}")
|
||||
return None
|
||||
|
||||
|
||||
logger.error(f"{self.workflow_id}:no role can process this msg:{msg.body}")
|
||||
return final_result
|
||||
|
||||
@@ -245,7 +245,7 @@ class Workflow:
|
||||
if llm_result_str == "ignore":
|
||||
r.state = "ignore"
|
||||
return r
|
||||
|
||||
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
|
||||
@@ -262,7 +262,7 @@ class Workflow:
|
||||
|
||||
r.send_msgs.append(new_msg)
|
||||
is_need_wait = True
|
||||
|
||||
|
||||
case "post_msg":# postmsg($target_id,$msg_content)
|
||||
if len(func_args) != 1:
|
||||
logger.error(f"parse postmsg failed! {func_call}")
|
||||
@@ -272,22 +272,22 @@ class Workflow:
|
||||
msg_content = func_item.body
|
||||
new_msg.set("_",target_id,msg_content)
|
||||
r.post_msgs.append(new_msg)
|
||||
|
||||
|
||||
case "call":# call($func_name,$args_str)
|
||||
r.calls.append(func_item)
|
||||
is_need_wait = True
|
||||
return True
|
||||
case "post_call": # post_call($func_name,$args_str)
|
||||
r.post_calls.append(func_item)
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
current_func : FunctionItem = None
|
||||
for line in lines:
|
||||
if line.startswith("##/"):
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
|
||||
|
||||
func_name,func_args = AgentMsg.parse_function_call(line[3:])
|
||||
current_func = FunctionItem(func_name,func_args)
|
||||
else:
|
||||
@@ -295,7 +295,7 @@ class Workflow:
|
||||
current_func.append_body(line + "\n")
|
||||
else:
|
||||
r.resp += line + "\n"
|
||||
|
||||
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
@@ -309,14 +309,14 @@ class Workflow:
|
||||
|
||||
async def role_post_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession):
|
||||
msg.sender = the_role.get_role_id()
|
||||
|
||||
|
||||
target_role = self.role_group.get(msg.target)
|
||||
if target_role:
|
||||
msg.target = target_role.get_role_id()
|
||||
logger.info(f"{msg.sender} post message {msg.msg_id} to inner role: {msg.target}")
|
||||
asyncio.create_task(self.role_process_msg(msg,target_role,workflow_chat_session))
|
||||
return
|
||||
|
||||
|
||||
target_workflow = self.sub_workflows.get(msg.target)
|
||||
if target_workflow:
|
||||
msg.target = target_workflow.workflow_id
|
||||
@@ -341,7 +341,7 @@ class Workflow:
|
||||
# msg.target = target_workflow.workflow_id
|
||||
logger.info(f"{msg.sender} send message {msg.msg_id} to sub workflow: {msg.target}")
|
||||
return await target_workflow._process_msg(msg)
|
||||
|
||||
|
||||
logger.info(f"{msg.sender} post message {msg.msg_id} to AIBus: {msg.target}")
|
||||
return await self.get_bus().send_message(msg)
|
||||
|
||||
@@ -352,8 +352,8 @@ class Workflow:
|
||||
func_node : AIFunction = self.workflow_env.get_ai_function(func_item.name)
|
||||
if func_node is None:
|
||||
return "execute failed,function not found"
|
||||
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
return result_str
|
||||
|
||||
async def role_post_call(self,func_item:FunctionItem,the_role:AIRole):
|
||||
@@ -363,7 +363,7 @@ class Workflow:
|
||||
def _format_msg_by_env_value(self,prompt:AgentPrompt):
|
||||
if self.workflow_env is None:
|
||||
return
|
||||
|
||||
|
||||
for msg in prompt.messages:
|
||||
old_content = msg.get("content")
|
||||
msg["content"] = old_content.format_map(self.workflow_env)
|
||||
@@ -372,15 +372,17 @@ class Workflow:
|
||||
all_inner_function = self.workflow_env.get_all_ai_functions()
|
||||
if all_inner_function is None:
|
||||
return None
|
||||
|
||||
|
||||
result_func = []
|
||||
for inner_func in all_inner_function:
|
||||
func_name = inner_func.get_name()
|
||||
if the_role.enable_function_list:
|
||||
if the_role.enable_function_list is not None:
|
||||
if len(the_role.enable_function_list) > 0:
|
||||
if func_name not in the_role.enable_function_list:
|
||||
logger.debug(f"ageint {self.agent_id} ignore inner func:{func_name}")
|
||||
logger.debug(f"agent {self.agent_id} ignore inner func:{func_name}")
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
this_func = {}
|
||||
this_func["name"] = func_name
|
||||
this_func["description"] = inner_func.get_description()
|
||||
@@ -399,17 +401,17 @@ class Workflow:
|
||||
func_node : AIFunction = self.workflow_env.get_ai_function(func_name)
|
||||
if func_node is None:
|
||||
return "execute failed,function not found"
|
||||
|
||||
|
||||
ineternal_call_record = AgentMsg.create_internal_call_msg(func_name,arguments,org_msg.get_msg_id(),org_msg.target)
|
||||
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
|
||||
inner_functions = self._get_inner_functions()
|
||||
|
||||
inner_functions = self._get_inner_functions(the_role)
|
||||
prompt.messages.append({"role":"function","content":result_str,"name":func_name})
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,
|
||||
the_role.agent.llm_model_name,the_role.agent.max_token_size,
|
||||
inner_functions)
|
||||
|
||||
|
||||
ineternal_call_record.result_str = task_result.result_str
|
||||
ineternal_call_record.done_time = time.time()
|
||||
org_msg.inner_call_chain.append(ineternal_call_record)
|
||||
@@ -419,13 +421,13 @@ class Workflow:
|
||||
return await self._role_execute_func(the_role,inner_func_call_node,prompt,org_msg,stack_limit-1)
|
||||
else:
|
||||
return task_result.result_str
|
||||
|
||||
|
||||
def _is_in_same_workflow(self,msg) -> bool:
|
||||
pass
|
||||
|
||||
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession):
|
||||
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession):
|
||||
msg.target = the_role.get_role_id()
|
||||
|
||||
|
||||
|
||||
prompt = AgentPrompt()
|
||||
prompt.append(the_role.agent.prompt)
|
||||
@@ -433,7 +435,7 @@ class Workflow:
|
||||
prompt.append(the_role.get_prompt())
|
||||
# prompt.append(self._get_function_prompt(the_role.get_name()))
|
||||
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||
|
||||
|
||||
#support group chat, user content include sender name!
|
||||
prompt.append(await self._get_prompt_from_session(workflow_chat_session))
|
||||
|
||||
@@ -443,15 +445,15 @@ class Workflow:
|
||||
|
||||
self._format_msg_by_env_value(prompt)
|
||||
inner_functions = self._get_inner_functions(the_role)
|
||||
|
||||
|
||||
async def _do_process_msg():
|
||||
#TODO: send msg to agent might be better?
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size(),inner_functions)
|
||||
result_str = task_result.result_str
|
||||
logger.info(f"{the_role.role_id} process {msg.sender}:{msg.body},llm str is :{result_str}")
|
||||
|
||||
|
||||
inner_func_call_node = task_result.result_message.get("function_call")
|
||||
|
||||
|
||||
if inner_func_call_node:
|
||||
#TODO to save more token ,can i use msg_prompt?
|
||||
result_str = await self._role_execute_func(the_role,inner_func_call_node,prompt,msg)
|
||||
@@ -461,7 +463,7 @@ class Workflow:
|
||||
postmsg.prev_msg_id = msg.get_msg_id()
|
||||
# might be craete a new msg.topic for this postmsg
|
||||
postmsg.topic = msg.topic
|
||||
|
||||
|
||||
await self.role_post_msg(postmsg,the_role,workflow_chat_session)
|
||||
if not self._is_in_same_workflow(postmsg):
|
||||
role_sesion = AIChatSession.get_session(the_role.get_role_id(),f"{postmsg.target}#{msg.topic}",self.db_file)
|
||||
@@ -469,14 +471,14 @@ class Workflow:
|
||||
else:
|
||||
# message will be saved in role.process_message
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
for post_call in result.post_calls:
|
||||
action_msg = msg.create_action_msg(post_call[0],post_call[1],the_role.get_role_id())
|
||||
workflow_chat_session.append(action_msg)
|
||||
await self.role_post_call(post_call,the_role)
|
||||
#save post_call
|
||||
|
||||
|
||||
result_prompt_str = ""
|
||||
match result.state:
|
||||
case "ignore":
|
||||
@@ -506,11 +508,11 @@ class Workflow:
|
||||
else:
|
||||
# message will be saved in role.process_message
|
||||
pass
|
||||
|
||||
|
||||
for call in result.calls:
|
||||
action_msg = msg.create_action_msg(call[0],call[1],call_result,the_role.get_role_id)
|
||||
call_result = await self.role_call(call,the_role)
|
||||
|
||||
|
||||
if call_result is not None:
|
||||
result_prompt_str += f"\ncall {call[0]} result is :{call_result}"
|
||||
#save action
|
||||
@@ -522,7 +524,7 @@ class Workflow:
|
||||
prompt.append(result_prompt)
|
||||
r = await _do_process_msg()
|
||||
return r
|
||||
|
||||
|
||||
return await _do_process_msg()
|
||||
|
||||
async def _get_prompt_from_session(self,chatsession:AIChatSession) -> AgentPrompt:
|
||||
@@ -533,9 +535,9 @@ class Workflow:
|
||||
result_prompt.messages.append({"role":"assistant","content":msg.body})
|
||||
else:
|
||||
result_prompt.messages.append({"role":"user","content":f"{msg.body}"})
|
||||
|
||||
|
||||
return result_prompt
|
||||
|
||||
|
||||
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
||||
pass
|
||||
|
||||
@@ -557,7 +559,7 @@ class Workflow:
|
||||
# if k == "role":
|
||||
# continue
|
||||
# else:
|
||||
#
|
||||
#
|
||||
# def _env_msg_handler(env_event:EnvironmentEvent) -> None:
|
||||
# the_msg:AgentMsg= self._env_event_to_msg(env_event)
|
||||
# self.role_post_msg
|
||||
|
||||
Reference in New Issue
Block a user