Workflow is almost done.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from enum import Enum
|
||||
import uuid
|
||||
import time
|
||||
import re
|
||||
|
||||
class AgentMsgState(Enum):
|
||||
RESPONSED = 0
|
||||
@@ -37,3 +38,22 @@ class AgentMsg:
|
||||
|
||||
def get_target(self) -> str:
|
||||
return self.target
|
||||
|
||||
@classmethod
|
||||
def parse_function_call(cls,func_string:str):
|
||||
match = re.search(r'\s*(\w+)\s*\(\s*(.*)\s*\)\s*', func_string)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
func_name = match.group(1)
|
||||
if func_name is None:
|
||||
return None
|
||||
if len(func_name) < 2:
|
||||
return None
|
||||
|
||||
params_string = match.group(2).strip()
|
||||
params = re.split(r'\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)', params_string)
|
||||
params = [param.strip('"') for param in params]
|
||||
|
||||
return func_name, params
|
||||
|
||||
|
||||
+11
-1
@@ -34,6 +34,7 @@ class AIBus:
|
||||
self.unhandle_handler = None
|
||||
|
||||
async def post_message(self,target_id,msg:AgentMsg,use_unhandle=True) -> bool:
|
||||
target_id = target_id.split(".")[0]
|
||||
handler = self.handlers.get(target_id)
|
||||
if handler:
|
||||
handler.queue.put_nowait(msg)
|
||||
@@ -62,6 +63,7 @@ class AIBus:
|
||||
return handler.results.get(msg_id)
|
||||
|
||||
async def send_message(self,target_id:str,msg:AgentMsg) -> AgentMsg:
|
||||
target_id = target_id.split(".")[0]
|
||||
post_result = await self.post_message(target_id,msg)
|
||||
if post_result is False:
|
||||
return None
|
||||
@@ -126,4 +128,12 @@ class AIBus:
|
||||
|
||||
handler.working_task = asyncio.create_task(self.process_queue(handler))
|
||||
|
||||
|
||||
|
||||
|
||||
#send message to target logic:
|
||||
# find target handler:
|
||||
# process_message(msg):
|
||||
# session = get_session(msg.sender,msg.target)
|
||||
|
||||
|
||||
# history: open(sender,target,topic)
|
||||
@@ -237,13 +237,13 @@ class AIChatSession:
|
||||
|
||||
def append_post(self,msg:AgentMsg) -> None:
|
||||
"""append msg to session, msg is post from session (owner => msg.target)"""
|
||||
assert msg.sender == self.owner_id,"post message means msg.sender == self.owner_id"
|
||||
#assert msg.sender == self.owner_id,"post message means msg.sender == self.owner_id"
|
||||
self.append(msg)
|
||||
|
||||
|
||||
def append_recv(self,msg:AgentMsg) -> None:
|
||||
"""append msg to session, msg is recv from msg'sender (msg.sender => owner)"""
|
||||
assert msg.target == self.owner_id,"recv message means msg.target == self.owner_id"
|
||||
#assert msg.target == self.owner_id,"recv message means msg.target == self.owner_id"
|
||||
self.append(msg)
|
||||
|
||||
#def attach_event_handler(self,handler) -> None:
|
||||
|
||||
@@ -6,6 +6,7 @@ class AIRole:
|
||||
def __init__(self) -> None:
|
||||
self.agent_instance_id : str = None
|
||||
self.role_name : str = None
|
||||
self.role_id :str = None # $workflow_id.$sub_workflow_id.$role_name
|
||||
self.fullname : str = None
|
||||
self.agent_name : str = None
|
||||
self.prompt : AgentPrompt = None
|
||||
@@ -19,6 +20,7 @@ class AIRole:
|
||||
return False
|
||||
self.role_name = name_node
|
||||
|
||||
|
||||
agent_id_node = config.get("agent")
|
||||
if agent_id_node is None:
|
||||
logging.error("agent id is not found!")
|
||||
@@ -35,7 +37,10 @@ class AIRole:
|
||||
intro_node = config.get("intro")
|
||||
if intro_node is not None:
|
||||
self.introduce = intro_node
|
||||
|
||||
|
||||
def get_role_id(self) -> str:
|
||||
return self.role_id
|
||||
|
||||
def get_intro(self) -> str:
|
||||
return self.introduce
|
||||
|
||||
@@ -48,6 +53,7 @@ class AIRole:
|
||||
class AIRoleGroup:
|
||||
def __init__(self) -> None:
|
||||
self.roles : dict[str,AIRole] = {}
|
||||
self.owner_name : str = None
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
for k,v in config.items():
|
||||
@@ -55,7 +61,7 @@ class AIRoleGroup:
|
||||
if role.load_from_config(v) is False:
|
||||
logging.error(f"load role {k} failed!")
|
||||
return False
|
||||
|
||||
role.role_id = self.owner_name + "." + k
|
||||
self.roles[k] = role
|
||||
|
||||
return True
|
||||
|
||||
+241
-68
@@ -33,9 +33,20 @@ class MessageFilter:
|
||||
return True
|
||||
|
||||
|
||||
class LLMResult:
|
||||
def __init__(self) -> None:
|
||||
self.state : str = "ignore"
|
||||
self.resp : str = ""
|
||||
self.post_msgs = []
|
||||
self.send_msgs = []
|
||||
self.calls = []
|
||||
self.post_calls = []
|
||||
|
||||
|
||||
class Workflow:
|
||||
def __init__(self) -> None:
|
||||
self.workflow_name : str = None
|
||||
self.workflow_id : str = None
|
||||
self.rule_prompt : AgentPrompt = None
|
||||
self.workflow_config = None
|
||||
self.role_group : dict = None
|
||||
@@ -62,6 +73,11 @@ class Workflow:
|
||||
logger.error("workflow config must have name")
|
||||
return False
|
||||
self.workflow_name = config.get("name")
|
||||
if self.owner_workflow is None:
|
||||
self.workflow_id = self.workflow_name
|
||||
else:
|
||||
self.workflow_id = self.owner_workflow.workflow_id + "." + self.workflow_name
|
||||
self.db_file = self.owner_workflow.db_file
|
||||
|
||||
#if config.get("rule_prompt") is None:
|
||||
# logger.error("workflow config must have rule_prompt")
|
||||
@@ -74,13 +90,14 @@ class Workflow:
|
||||
logger.error("workflow config must have roles")
|
||||
return False
|
||||
self.role_group = AIRoleGroup()
|
||||
self.role_group.owner_name = self.workflow_id
|
||||
if self.role_group.load_from_config(config.get("roles")) is False:
|
||||
logger.error("Workflow load role_group failed")
|
||||
return False
|
||||
|
||||
if config.get("input_filter") is not None:
|
||||
if config.get("filter") is not None:
|
||||
self.input_filter = MessageFilter()
|
||||
if self.input_filter.load_from_config(config.get("input_filter")) is False:
|
||||
if self.input_filter.load_from_config(config.get("filter")) is False:
|
||||
logger.error("Workflow load input_filter failed")
|
||||
return False
|
||||
|
||||
@@ -98,15 +115,52 @@ class Workflow:
|
||||
for k,v in config.items():
|
||||
sub_workflow = Workflow()
|
||||
sub_workflow.set_owner(self)
|
||||
|
||||
if sub_workflow.load_from_config(v) is False:
|
||||
logger.error(f"load sub workflow {k} failed!")
|
||||
return False
|
||||
self.sub_workflows[k] = sub_workflow
|
||||
return True
|
||||
|
||||
def _parse_msg_target(self,s:str)->list[str]:
|
||||
return s.split(".")
|
||||
|
||||
async def _forword_msg(self,inner_obj_id,msg):
|
||||
i : int = 1
|
||||
current_workflow = self
|
||||
while i < len(inner_obj_id):
|
||||
if i == len(inner_obj_id) - 1:
|
||||
the_role : AIRole = current_workflow.role_group.get(inner_obj_id[i])
|
||||
if the_role is not None:
|
||||
return await current_workflow.role_process_msg(msg,the_role)
|
||||
sub_workflow = current_workflow.sub_workflows.get(inner_obj_id[i])
|
||||
if sub_workflow is not None:
|
||||
return await sub_workflow.process_msg(msg)
|
||||
logger.error(f"{msg.target} not found! forword message failed!")
|
||||
return None
|
||||
else:
|
||||
current_workflow = current_workflow.sub_workflows.get(inner_obj_id[i])
|
||||
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
|
||||
|
||||
|
||||
async def _process_msg(self,msg:AgentMsg):
|
||||
# workflow can be a message handler, but never be a message sender
|
||||
# all message forword to roles or sub workflow
|
||||
# workflow no chatsession record, but role have
|
||||
|
||||
final_result = None
|
||||
chatsession = None
|
||||
|
||||
targets = self._parse_msg_target(msg.target)
|
||||
if len(targets) > 1:
|
||||
return await self._forword_msg(targets,msg)
|
||||
|
||||
if self.input_filter is not None:
|
||||
select_role_id = self.input_filter.select(msg)
|
||||
if select_role_id is not None:
|
||||
@@ -115,35 +169,206 @@ class Workflow:
|
||||
logger.error(f"input_filter return invalid role id:{select_role_id}, role not found in role_group")
|
||||
return None
|
||||
|
||||
result = await self._role_process_msg(msg,select_role)
|
||||
result = await self.role_process_msg(msg,select_role)
|
||||
if result is None:
|
||||
logger.error(f"_process_msg return None for :{msg}")
|
||||
return
|
||||
if chatsession is not None:
|
||||
chatsession.append_post(result)
|
||||
|
||||
final_result = result
|
||||
else:
|
||||
logger.error(f"input_filter return None for :{msg}")
|
||||
return
|
||||
|
||||
else:
|
||||
# no input filter, we would process all message, slowly,not suggest to use
|
||||
results = {}
|
||||
final_result:AgentMsg = None
|
||||
for this_role in self.role_group.roles.values():
|
||||
# TODO : we would do this in parallel
|
||||
a_result = await self._role_process_msg(msg,this_role)
|
||||
a_result = await self.role_process_msg(msg,this_role)
|
||||
results[this_role.get_name()] = a_result
|
||||
|
||||
# merge result from all roles
|
||||
# TODO: one input msg can have multiple result msg, at this while ,we only support one result msg
|
||||
final_result:AgentMsg = self._merge_msg_result(results)
|
||||
if chatsession is not None:
|
||||
chatsession.append_post(final_result)
|
||||
final_result = a_result
|
||||
|
||||
return final_result
|
||||
|
||||
@classmethod
|
||||
def prase_llm_result(cls,llm_result_str:str)->LLMResult:
|
||||
r = LLMResult()
|
||||
if llm_result_str is None:
|
||||
r.state = "ignore"
|
||||
return r
|
||||
if llm_result_str == "ignore":
|
||||
r.state = "ignore"
|
||||
return r
|
||||
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
for line in lines:
|
||||
func_call = AgentMsg.parse_function_call(line)
|
||||
if func_call:
|
||||
func_args = func_call[1]
|
||||
match func_call[0]:
|
||||
case "sendmsg":# sendmsg($target_id,$msg_content)
|
||||
if len(func_args) != 2:
|
||||
logger.error(f"parse sendmsg failed! {func_call}")
|
||||
continue
|
||||
new_msg = AgentMsg()
|
||||
target_id = func_args[0]
|
||||
msg_content = func_args[1]
|
||||
new_msg.set("_",target_id,msg_content)
|
||||
|
||||
r.send_msgs.append(new_msg)
|
||||
is_need_wait = True
|
||||
continue
|
||||
case "postmsg":# postmsg($target_id,$msg_content)
|
||||
if len(func_args) != 2:
|
||||
logger.error(f"parse postmsg failed! {func_call}")
|
||||
continue
|
||||
new_msg = AgentMsg()
|
||||
target_id = func_args[1]
|
||||
msg_content = func_args[2]
|
||||
new_msg.set("_",target_id,msg_content)
|
||||
r.post_msgs.append(new_msg)
|
||||
continue
|
||||
case "call":# call($func_name,$args_str)
|
||||
r.calls.append(func_call)
|
||||
is_need_wait = True
|
||||
continue
|
||||
case "post_call": # post_call($func_name,$args_str)
|
||||
r.post_calls.append(func_call)
|
||||
continue
|
||||
|
||||
r.resp += line + "\n"
|
||||
else:
|
||||
r.resp += line + "\n"
|
||||
|
||||
if is_need_wait:
|
||||
r.state = "waiting"
|
||||
else:
|
||||
r.state = "reponsed"
|
||||
|
||||
return r
|
||||
|
||||
async def role_post_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||
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.id} to inner role: {msg.target}")
|
||||
asyncio.create_task(self.role_process_msg(msg,target_role))
|
||||
return
|
||||
|
||||
target_workflow = self.sub_workflows.get(msg.target)
|
||||
if target_workflow:
|
||||
msg.target = target_workflow.workflow_id
|
||||
logger.info(f"{msg.sender} post message {msg.id} to sub workflow: {msg.target}")
|
||||
asyncio.create_task(target_workflow._process_msg(msg))
|
||||
|
||||
logger.info(f"{msg.sender} post message {msg.id} to AIBus: {msg.target}")
|
||||
await self.get_bus().post_message(msg.target,msg)
|
||||
return
|
||||
|
||||
|
||||
async def role_send_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||
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} send message {msg.id} to inner role: {msg.target}")
|
||||
return await self.role_process_msg(msg,target_role)
|
||||
|
||||
|
||||
target_workflow = self.sub_workflows.get(msg.target)
|
||||
if target_workflow:
|
||||
# msg.target = target_workflow.workflow_id
|
||||
logger.info(f"{msg.sender} send message {msg.id} to sub workflow: {msg.target}")
|
||||
return await target_workflow._process_msg(msg)
|
||||
|
||||
logger.info(f"{msg.sender} post message {msg.id} to AIBus: {msg.target}")
|
||||
return await self.get_bus().send_message(msg.target,msg)
|
||||
|
||||
async def role_call(self,call:tuple,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} call {call[0]} with args {call[1]}")
|
||||
return """{result:"timeout"}"""
|
||||
|
||||
async def role_post_call(self,call:tuple,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} post call {call[0]} with args {call[1]}")
|
||||
return
|
||||
|
||||
|
||||
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||
session_topic = f"{msg.sender}#{msg.topic}"
|
||||
session_owner = the_role.get_role_id()
|
||||
chatsession : AIChatSession = AIChatSession.get_session(session_owner,session_topic,self.db_file)
|
||||
if chatsession is None:
|
||||
logger.error(f"get session {session_topic}@{session_owner} failed!")
|
||||
return None
|
||||
|
||||
prompt = AgentPrompt()
|
||||
prompt.append(the_role.agent.prompt)
|
||||
prompt.append(the_role.get_prompt())
|
||||
|
||||
# prompt.append(self.get_workflow_rule_prompt())
|
||||
# prompt.append(self._get_function_prompt(the_role.get_name()))
|
||||
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||
prompt.append(await self._get_prompt_from_session(chatsession))
|
||||
|
||||
msg_prompt = AgentPrompt()
|
||||
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||
prompt.append(msg_prompt)
|
||||
|
||||
|
||||
async def _do_process_msg():
|
||||
#TODO: send msg to agent might be better?
|
||||
result_str = await ComputeKernel().do_llm_completion(prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size())
|
||||
result = Workflow.prase_llm_result(result_str)
|
||||
|
||||
|
||||
for postmsg in result.post_msgs:
|
||||
postmsg.topic = msg.topic
|
||||
await self.role_post_msg(the_role,postmsg)
|
||||
|
||||
for post_call in result.post_calls:
|
||||
await self.role_post_call(post_call,the_role)
|
||||
|
||||
|
||||
result_prompt_str = ""
|
||||
match result.state:
|
||||
case "ignore":
|
||||
return None
|
||||
case "reponsed":
|
||||
resp_msg = AgentMsg()
|
||||
resp_msg.topic = msg.topic
|
||||
resp_msg.set(session_owner,msg.sender,result.resp)
|
||||
|
||||
chatsession.append_recv(msg)
|
||||
chatsession.append_post(resp_msg)
|
||||
return resp_msg
|
||||
case "waiting":
|
||||
# TODO: Use role:"function" would be better
|
||||
for sendmsg in result.send_msgs:
|
||||
target = sendmsg.target
|
||||
sendmsg.topic = msg.topic
|
||||
send_resp = await self.role_send_msg(sendmsg,the_role)
|
||||
if send_resp is not None:
|
||||
result_prompt_str += f"\n{target} response is :{send_resp.body}"
|
||||
|
||||
for call in result.calls:
|
||||
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}"
|
||||
|
||||
result_prompt = AgentPrompt()
|
||||
result_prompt.messages = [{"role":"user","content":result_prompt_str}]
|
||||
prompt.append(result_prompt)
|
||||
r = await _do_process_msg()
|
||||
return r
|
||||
|
||||
return await _do_process_msg()
|
||||
|
||||
|
||||
#obsolete
|
||||
async def _role_process_msg(self,msg:AgentMsg,the_role:AIRole) -> None:
|
||||
# TODO : we just record role's chatsession, but in future, we would record workflow's chatsession(like a groupo chat)
|
||||
session_topic = f"{the_role.get_name()}#{msg.sender}#{msg.topic}"
|
||||
@@ -162,7 +387,6 @@ class Workflow:
|
||||
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||
|
||||
prompt.append(await self._get_prompt_from_session(chatsession))
|
||||
#prompt.append(await self._get_prompt_from_session(chatsession,the_role.get_name())) # chat context
|
||||
|
||||
msg_prompt = AgentPrompt()
|
||||
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||
@@ -180,7 +404,7 @@ class Workflow:
|
||||
resp = await callchain.exec()
|
||||
if callchain.have_result():
|
||||
# generator proc resp prompt with WAITING state
|
||||
#proc_resp_prompt:AgentPrompt = self._get_resp_prompt(resp,msg,the_role,prompt,chatsession)
|
||||
proc_resp_prompt:AgentPrompt = self._get_resp_prompt(resp,msg,the_role,prompt,chatsession)
|
||||
final_result = await ComputeKernel().do_llm_completion(proc_resp_prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size())
|
||||
return final_result
|
||||
|
||||
@@ -218,31 +442,18 @@ class Workflow:
|
||||
chatsession.append_post(resp_msg)
|
||||
return resp_msg
|
||||
|
||||
async def _pop_msg(self) -> AgentMsg:
|
||||
pass
|
||||
|
||||
def _get_chat_session_for_msg(self,msg:AgentMsg) -> AIChatSession:
|
||||
pass
|
||||
|
||||
async def _get_prompt_from_session(self,chatsession:AIChatSession) -> AgentPrompt:
|
||||
messages = chatsession.read_history() # read last 10 message
|
||||
result_prompt = AgentPrompt()
|
||||
for msg in reversed(messages):
|
||||
if msg.target == chatsession.owner_id:
|
||||
result_prompt.messages.append({"role":"user","content":f"{msg.sender}:{msg.body}"})
|
||||
if msg.sender == chatsession.owner_id:
|
||||
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_msg_queue(self,session_id:str):
|
||||
pass
|
||||
|
||||
def _merge_msg_result(self,results:dict) -> AgentMsg:
|
||||
# TODO: one input msg can have multiple result msg, at this while ,we only support one result msg
|
||||
for k,v in results.items():
|
||||
if v is not None:
|
||||
return v
|
||||
|
||||
def _get_function_prompt(self,role_name:str) -> AgentPrompt:
|
||||
pass
|
||||
@@ -250,48 +461,10 @@ class Workflow:
|
||||
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
||||
pass
|
||||
|
||||
def _get_resp_prompt(self,resp:str,msg:AgentMsg,role:AIRole,prompt:AgentPrompt) -> AgentPrompt:
|
||||
pass
|
||||
|
||||
def get_workflow_rule_prompt(self) -> AgentPrompt:
|
||||
return self.rule_prompt
|
||||
|
||||
def _get_llm_result_type(self,llm_resp_str:str) -> str:
|
||||
if llm_resp_str == "ignore":
|
||||
return "ignore"
|
||||
|
||||
if llm_resp_str.find("sendmsg(") != -1:
|
||||
return "send_message"
|
||||
|
||||
if llm_resp_str.find("postmsg(") != -1:
|
||||
return "post_message"
|
||||
|
||||
if llm_resp_str.find("call(") != -1:
|
||||
return "function"
|
||||
|
||||
return "text"
|
||||
|
||||
def _parse_function_call_chain(self,llm_resp_str) -> CallChain:
|
||||
pass
|
||||
|
||||
def _parse_to_msg(self,llm_resp_str) -> AgentMsg:
|
||||
lines = llm_resp_str.splitlines()
|
||||
for line in lines:
|
||||
if line.startswith("sendmsg("):
|
||||
line = line[8:]
|
||||
_index = line.find(",")
|
||||
msg = AgentMsg()
|
||||
msg.set("",line[:_index],line[_index+1:])
|
||||
return msg
|
||||
|
||||
if line.startswith("postmsg("):
|
||||
line = line[8:]
|
||||
_index = line.find(",")
|
||||
msg = AgentMsg()
|
||||
msg.set("",line[:_index],line[_index+1:])
|
||||
return msg
|
||||
|
||||
return None
|
||||
|
||||
def get_workflow(self,workflow_name:str):
|
||||
"""get workflow from known workflow list or sub workflow list"""
|
||||
|
||||
@@ -25,6 +25,20 @@ class WorkflowManager:
|
||||
async def get_agent_default_workflow(self,agent_id:str) -> Workflow:
|
||||
pass
|
||||
|
||||
|
||||
async def _load_workflow_agents(self,workflow:Workflow) -> bool:
|
||||
for v in workflow.role_group.roles.values():
|
||||
agent = await AgentManager().get(v.agent_name)
|
||||
if agent is None:
|
||||
logger.error(f"load agent {v.agent_name} failed!")
|
||||
return False
|
||||
v.agent = agent
|
||||
|
||||
for sub_workflow in workflow.sub_workflows.values():
|
||||
if await self._load_workflow_agents(sub_workflow) is False:
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_workflow(self,workflow_id:str) -> Workflow:
|
||||
the_workflow : Workflow = self.loaded_workflow.get(workflow_id)
|
||||
if the_workflow:
|
||||
@@ -39,14 +53,9 @@ class WorkflowManager:
|
||||
if the_workflow is None:
|
||||
logger.warn(f"load workflow {workflow_id} from media failed!")
|
||||
|
||||
for v in the_workflow.role_group.roles.values():
|
||||
agent = await AgentManager().get(v.agent_name)
|
||||
if agent is None:
|
||||
logger.error(f"load agent {v.agent_name} failed!")
|
||||
return None
|
||||
v.agent = agent
|
||||
|
||||
|
||||
if await self._load_workflow_agents(the_workflow) is False:
|
||||
return None
|
||||
|
||||
return the_workflow
|
||||
|
||||
async def _load_workflow_from_media(self,workflow_media:PackageMediaInfo) -> Workflow:
|
||||
@@ -64,10 +73,12 @@ class WorkflowManager:
|
||||
config_data = await config_file.read()
|
||||
config = toml.loads(config_data)
|
||||
result_workflow = Workflow()
|
||||
result_workflow.db_file = self.db_file
|
||||
|
||||
if result_workflow.load_from_config(config) is False:
|
||||
logger.error(f"load workflow from {workflow_media} failed!")
|
||||
return None
|
||||
result_workflow.db_file = self.db_file
|
||||
|
||||
return result_workflow
|
||||
except Exception as e:
|
||||
logger.error(f"read workflow.toml cfg from {workflow_media} failed! unexpected error occurred: {str(e)}")
|
||||
|
||||
@@ -41,16 +41,15 @@ class AIOS_Shell:
|
||||
self.current_topic = "default"
|
||||
|
||||
async def _handle_no_target_msg(self,bus:AIBus,msg:AgentMsg) -> bool:
|
||||
agent : AIAgent = await AgentManager().get(msg.target)
|
||||
target_id = msg.target.split(".")[0]
|
||||
agent : AIAgent = await AgentManager().get(target_id)
|
||||
if agent is not None:
|
||||
bus.register_message_handler(msg.target,agent._process_msg)
|
||||
bus.register_message_handler(target_id,agent._process_msg)
|
||||
return True
|
||||
|
||||
a_workflow = await WorkflowManager().get_workflow(msg.target)
|
||||
a_workflow = await WorkflowManager().get_workflow(target_id)
|
||||
if a_workflow is not None:
|
||||
bus.register_message_handler(msg.target,a_workflow._process_msg)
|
||||
for subflow in a_workflow.sub_workflows.values():
|
||||
bus.register_message_handler(subflow.workflow_name,subflow._process_msg)
|
||||
bus.register_message_handler(target_id,a_workflow._process_msg)
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -79,7 +78,7 @@ class AIOS_Shell:
|
||||
agent_msg = AgentMsg()
|
||||
agent_msg.set(sender,target_id,msg)
|
||||
agent_msg.topic = topic
|
||||
resp = await AIBus().get_default_bus().send_message(target_id,agent_msg)
|
||||
resp = await AIBus.get_default_bus().send_message(target_id,agent_msg)
|
||||
if resp is not None:
|
||||
return resp.body
|
||||
else:
|
||||
@@ -111,10 +110,11 @@ class AIOS_Shell:
|
||||
case 'history':
|
||||
num = 10
|
||||
offset = 0
|
||||
if len(args) >= 1:
|
||||
num = args[0]
|
||||
if len(args) >= 2:
|
||||
offset = args[1]
|
||||
if args is not None:
|
||||
if len(args) >= 1:
|
||||
num = args[0]
|
||||
if len(args) >= 2:
|
||||
offset = args[1]
|
||||
|
||||
db_path = ""
|
||||
if await self.is_agent(self.current_target):
|
||||
@@ -140,37 +140,43 @@ class AIOS_Shell:
|
||||
history = FileHistory('history.txt')
|
||||
session = PromptSession(history=history)
|
||||
|
||||
def parse_function_call(s):
|
||||
match = re.match(r'(\w+)\((.*)\)$', s)
|
||||
if match:
|
||||
func_name = match.group(1)
|
||||
args_str = match.group(2)
|
||||
|
||||
args = []
|
||||
buffer = ''
|
||||
quote_count = 0 # Count of single or double quotes
|
||||
for char in args_str:
|
||||
|
||||
if char in ['"', "'"]:
|
||||
quote_count += 1
|
||||
if char == ',' and quote_count % 2 == 0: # ',' is outside of quotes
|
||||
args.append(buffer.strip())
|
||||
buffer = ''
|
||||
else:
|
||||
buffer += char
|
||||
if buffer:
|
||||
args.append(buffer.strip())
|
||||
|
||||
return func_name, args
|
||||
else:
|
||||
def parse_function_call(func_string):
|
||||
match = re.search(r'\s*(\w+)\s*\(\s*(.*)\s*\)\s*', func_string)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
func_name = match.group(1)
|
||||
params_string = match.group(2).strip()
|
||||
params = re.split(r'\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)', params_string)
|
||||
params = [param.strip('"') for param in params]
|
||||
if len(params[0]) == 0:
|
||||
params = None
|
||||
|
||||
return func_name, params
|
||||
|
||||
|
||||
async def main():
|
||||
print("aios shell prepareing...")
|
||||
logging.basicConfig(filename="aios_shell.log",filemode="w",level=logging.INFO,format='[%(asctime)s]%(name)s[%(levelname)s]: %(message)s')
|
||||
logging.basicConfig(filename="aios_shell.log",filemode="w",encoding='utf-8',
|
||||
level=logging.INFO,
|
||||
format='[%(asctime)s]%(name)s[%(levelname)s]: %(message)s')
|
||||
shell = AIOS_Shell("user")
|
||||
await shell.initial()
|
||||
|
||||
s = """了解。首先,我们需要进行方案讨论,定出一致的活动策略。我将任务分解如下:
|
||||
财务组: 分析可见的预算,提供一份合理并被执行的财务方案。
|
||||
行程预订组: 硅谷自然迷人的地方众多,寻找适合11人秋游的地点,以及一个可行的周末日期。策划一个一天或两天的安排,包括选择有南瓜园的地方,采摘苹果,参观当地的酗酒作坊等秋游活动。
|
||||
嘉宾对接组: 把个人的食品饮料或过敏食物的需求事先了解并计入行程内。
|
||||
酒店预订组:根据行程预订组的日期安排,活动时间在1天还是2天,在这个之内找一个合适的住宿,试着保持让住宿在预算边界以内。
|
||||
活动摄像组: 准备活动拍摄与剪辑方案。\n\n然后,我将把这些拆分后的任务发来小组。
|
||||
sendmsg(财务组,分析预算并提供一份财务方案.)
|
||||
sendmsg(行程预订组,找出适合秋游的地方和日期.)
|
||||
sendmsg(嘉宾对接组,了解个人的饮食需求.)
|
||||
sendmsg(酒店预订组,查询并预订住宿.)
|
||||
sendmsg(活动摄像组,提供活动拍摄方案.)
|
||||
经过一两天的准备,一切就绪之后,我将向工作人员发送最后的行程计划,
|
||||
"""
|
||||
r = Workflow.prase_llm_result(s)
|
||||
print(f"aios shell {shell.get_version()} ready.")
|
||||
|
||||
completer = WordCompleter(['send($target,$msg,$topic)',
|
||||
|
||||
Reference in New Issue
Block a user