Refactor before imporve knowledge base.

This commit is contained in:
Liu Zhicong
2023-10-18 11:19:11 -07:00
parent 760087d945
commit b74b86b4d4
19 changed files with 683 additions and 445 deletions
+150
View File
@@ -0,0 +1,150 @@
<mxfile host="Electron" modified="2023-10-10T07:47:12.198Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.0.2 Chrome/114.0.5735.289 Electron/25.8.4 Safari/537.36" etag="ooen5M4lIGDak3P-0D5_" version="22.0.2" type="device" pages="5">
<diagram name="Init" id="eZ0Fsh2vPRb0vo3J8o-a">
<mxGraphModel dx="2286" dy="1168" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="IzO59fDZ9m1edTcSyALi-11" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="90" width="155" height="60" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-9" value="" style="verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;strokeWidth=1;shape=mxgraph.mockup.containers.userFemale;strokeColor=#666666;strokeColor2=#008cff;" parent="1" vertex="1">
<mxGeometry x="45" y="95" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-12" value="Main Page" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="150" width="155" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-13" value="AIGC" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="210" width="155" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-20" value="" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shape=mxgraph.basic.rect;fillColor2=none;strokeWidth=1;size=20;indent=5;" parent="1" vertex="1">
<mxGeometry x="195" y="90" width="565" height="420" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-21" value="My Devices" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="180" width="155" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-22" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" parent="1" vertex="1">
<mxGeometry x="312.5" y="130" width="340" height="340" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-23" value="Config LLM Kernel:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="320" y="145" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-24" value="Config Owner Info:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="320" y="220" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-25" value="Done" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.buttons.button;strokeColor=#666666;fontColor=#ffffff;mainText=;buttonStyle=round;fontSize=17;fontStyle=1;fillColor=#008cff;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="420" y="410" width="150" height="50" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-26" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="240" width="155" height="270" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-27" value="&lt;font style=&quot;font-size: 10px;&quot;&gt;Version 0.5.2&lt;br&gt;http://www.opendan.ai&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="480" width="155" height="30" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-28" value="" style="shape=mxgraph.signs.science.nuclear_2;html=1;pointerEvents=1;fillColor=#000000;strokeColor=none;verticalLabelPosition=bottom;verticalAlign=top;align=center;sketch=0;" parent="1" vertex="1">
<mxGeometry x="45" y="155.5" width="20" height="19" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-31" value="" style="shape=mxgraph.signs.tech.ethernet;html=1;pointerEvents=1;fillColor=#000000;strokeColor=none;verticalLabelPosition=bottom;verticalAlign=top;align=center;sketch=0;" parent="1" vertex="1">
<mxGeometry x="45" y="190" width="20.63" height="10" as="geometry" />
</mxCell>
<mxCell id="IzO59fDZ9m1edTcSyALi-32" value="" style="shape=mxgraph.signs.travel.information_2;html=1;pointerEvents=1;fillColor=#000000;strokeColor=none;verticalLabelPosition=bottom;verticalAlign=top;align=center;sketch=0;" parent="1" vertex="1">
<mxGeometry x="49.900000000000006" y="216" width="10.84" height="18" as="geometry" />
</mxCell>
<mxCell id="l8k4_rfZMrNWla8Lv80Y-1" value="AI Store" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="40" y="240" width="155" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="EX4l-TP_pYMqB1o-9Pjg" name="MainPage">
<mxGraphModel dx="1577" dy="806" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="A7pxehO7BnMPWpYIlLSW-1" value="" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shape=mxgraph.basic.rect;fillColor2=none;strokeWidth=1;size=20;indent=5;" vertex="1" parent="1">
<mxGeometry x="97.5" y="66" width="565" height="580" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-3" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="127.5" y="231" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-2" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="142.5" y="201" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-4" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="227.5" y="231" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-5" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="242.5" y="201" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-6" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="327.5" y="231" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="342.5" y="201" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-8" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="422.5" y="231" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-9" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="437.5" y="201" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-10" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="517.5" y="231" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-11" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="532.5" y="201" width="50" height="50" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-12" value="My Agents:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="117.5" y="171" width="70" height="30" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-17" value="" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shadow=0;dashed=0;strokeWidth=1;shape=mxgraph.android.quickscroll3;dy=0.5;fillColor=#33b5e5;strokeColor=#66D5F5;rotation=90;" vertex="1" parent="1">
<mxGeometry x="380.5" y="66" width="6" height="520" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-19" value="" style="shape=cross;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="610.5" y="175" width="20" height="20" as="geometry" />
</mxCell>
<mxCell id="A7pxehO7BnMPWpYIlLSW-20" value="System Stauts" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="120" y="80" width="520" height="80" as="geometry" />
</mxCell>
<mxCell id="38aqMLvnZxr78S6UhFXi-2" value="" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="127.5" y="740" width="497" height="240" as="geometry" />
</mxCell>
<mxCell id="38aqMLvnZxr78S6UhFXi-3" value="Agent Detials:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="298.5" y="750" width="139" height="30" as="geometry" />
</mxCell>
<mxCell id="38aqMLvnZxr78S6UhFXi-4" value="My Knowledge Base:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="117.5" y="330" width="132.5" height="30" as="geometry" />
</mxCell>
<mxCell id="38aqMLvnZxr78S6UhFXi-6" value="Logs/Command Line" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="117.5" y="570" width="122.5" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="x4dUm2vkSZsrNgmtw8U3" name="Devices">
<mxGraphModel dx="2286" dy="1168" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="nG_j26PwBAeOLUIgazIM-1" value="" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shape=mxgraph.basic.rect;fillColor2=none;strokeWidth=1;size=20;indent=5;" vertex="1" parent="1">
<mxGeometry x="130" y="80" width="565" height="580" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="5KzlG5ec7zi2r4DX32yK" name="AIGC">
<mxGraphModel dx="2286" dy="1168" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
</root>
</mxGraphModel>
</diagram>
<diagram id="qqyI6l9TxLyHAeHWymlS" name="AI Store">
<mxGraphModel dx="2286" dy="1168" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
</root>
</mxGraphModel>
</diagram>
</mxfile>
-1
View File
@@ -8,5 +8,4 @@ max_token_size=4000
role = "system"
content = """
Your name is Lachlan, and you are my advanced private Spanish tutor.
You are also a local guide familiar with the history of the Inca Empire. While teaching me Spanish, you will introduce some related historical and cultural origins.
"""
+2 -2
View File
@@ -1,7 +1,7 @@
from .environment import Environment,EnvironmentEvent
from .agent_message import AgentMsg,AgentMsgStatus,AgentMsgType
from .agent_base import AgentMsg,AgentMsgStatus,AgentMsgType,AgentPrompt
from .chatsession import AIChatSession
from .agent import AIAgent,AIAgentTemplete,AgentPrompt
from .agent import AIAgent,AIAgentTemplete
from .compute_kernel import ComputeKernel,ComputeTask,ComputeTaskResult,ComputeTaskState,ComputeTaskType
from .compute_node import ComputeNode,LocalComputeNode
from .open_ai_node import OpenAI_ComputeNode
+117 -182
View File
@@ -10,73 +10,20 @@ import shlex
import datetime
import copy
from .agent_message import AgentMsg, AgentMsgStatus, AgentMsgType,FunctionItem,LLMResult
from .agent_base import AgentMsg, AgentMsgStatus, AgentMsgType,FunctionItem,LLMResult,AgentPrompt
from .chatsession import AIChatSession
from .compute_task import ComputeTaskResult,ComputeTaskResultCode
from .ai_function import AIFunction
from .environment import Environment
from .contact_manager import ContactManager,Contact,FamilyMember
from .knowledge_base import KnowledgeBase
from .compute_kernel import ComputeKernel
from .bus import AIBus
from knowledge import *
logger = logging.getLogger(__name__)
class AgentPrompt:
def __init__(self,prompt_str = None) -> None:
self.messages = []
if prompt_str:
self.messages.append({"role":"user","content":prompt_str})
self.system_message = None
def as_str(self)->str:
result_str = ""
if self.system_message:
result_str += self.system_message.get("role") + ":" + self.system_message.get("content") + "\n"
if self.messages:
for msg in self.messages:
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 = copy.deepcopy(prompt.system_message)
else:
self.system_message["content"] += prompt.system_message.get("content")
self.messages.extend(prompt.messages)
def get_prompt_token_len(self):
result = 0
if self.system_message:
result += len(self.system_message.get("content"))
for msg in self.messages:
result += len(msg.get("content"))
return result
def load_from_config(self,config:list) -> bool:
if isinstance(config,list) is not True:
logger.error("prompt is not list!")
return False
self.messages = []
for msg in config:
if msg.get("role") == "system":
self.system_message = msg
else:
self.messages.append(msg)
return True
class AIAgentTemplete:
def __init__(self) -> None:
@@ -106,10 +53,13 @@ class AIAgentTemplete:
class AIAgent:
def __init__(self) -> None:
self.role_prompt:AgentPrompt = None
self.agent_prompt:AgentPrompt = None
self.agent_think_prompt:AgentPrompt = None
self.llm_model_name:str = None
self.max_token_size:int = 3600
self.agent_id:str = None
self.template_id:str = None
self.fullname:str = None
@@ -122,6 +72,9 @@ class AIAgent:
self.contact_prompt_str = None
self.history_len = 10
self.learn_token_limit = 500
self.learn_prompt = None
self.chat_db = None
self.unread_msg = Queue() # msg from other agent
self.owner_env : Environment = None
@@ -190,76 +143,30 @@ class AIAgent:
self.history_len = int(config.get("history_len"))
return True
def get_id(self) -> str:
return self.agent_id
def _get_llm_result_type(self,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
def get_fullname(self) -> str:
return self.fullname
lines = llm_result_str.splitlines()
is_need_wait = False
def get_template_id(self) -> str:
return self.template_id
def check_args(func_item:FunctionItem):
match func_name:
case "send_msg":# sendmsg($target_id,$msg_content)
if len(func_args) != 1:
logger.error(f"parse sendmsg failed! {func_name}")
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
msg_content = func_item.body
new_msg.set(self.agent_id,target_id,msg_content)
def get_llm_model_name(self) -> str:
return self.llm_model_name
r.send_msgs.append(new_msg)
is_need_wait = True
def get_max_token_size(self) -> int:
return self.max_token_size
case "post_msg":# postmsg($target_id,$msg_content)
if len(func_args) != 1:
logger.error(f"parse postmsg failed! {func_name}")
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
msg_content = func_item.body
new_msg.set(self.agent_id,target_id,msg_content)
r.post_msgs.append(new_msg)
def get_llm_learn_token_limit(self) -> int:
return self.learn_token_limit
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
def get_learn_prompt(self) -> AgentPrompt:
return self.learn_prompt
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()
def get_agent_role_prompt(self) -> AgentPrompt:
return self.role_prompt
func_name,func_args = AgentMsg.parse_function_call(line[3:])
current_func = FunctionItem(func_name,func_args)
else:
if current_func:
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:
r.state = "reponsed"
return r
def _get_remote_user_prompt(self,remote_user:str) -> AgentPrompt:
cm = ContactManager.get_instance()
@@ -314,18 +221,18 @@ class AIAgent:
return result_func,result_len
async def _execute_func(self,inenr_func_call_node:dict,prompt:AgentPrompt,org_msg:AgentMsg,stack_limit = 5) -> [str,int]:
from .compute_kernel import ComputeKernel
func_name = inenr_func_call_node.get("name")
arguments = json.loads(inenr_func_call_node.get("arguments"))
async def _execute_func(self,inner_func_call_node:dict,prompt:AgentPrompt,inner_functions,org_msg:AgentMsg=None,stack_limit = 5) -> ComputeTaskResult:
func_name = inner_func_call_node.get("name")
arguments = json.loads(inner_func_call_node.get("arguments"))
logger.info(f"llm execute inner func:{func_name} ({json.dumps(arguments)})")
func_node : AIFunction = self.owner_env.get_ai_function(func_name)
if func_node is None:
result_str = f"execute {func_name} error,function not found"
else:
ineternal_call_record = AgentMsg.create_internal_call_msg(func_name,arguments,org_msg.get_msg_id(),org_msg.target)
if org_msg:
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:
@@ -334,26 +241,28 @@ class AIAgent:
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)
if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"llm compute error:{task_result.error_str}")
return task_result.error_str,1
return task_result
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 org_msg:
org_msg.inner_call_chain.append(ineternal_call_record)
inner_func_call_node = None
if stack_limit > 0:
result_message = task_result.result.get("message")
result_message : dict = task_result.result.get("message")
if result_message:
inner_func_call_node = 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)
else:
return task_result.result_str,0
return task_result
async def _get_agent_prompt(self) -> AgentPrompt:
return self.agent_prompt
@@ -385,11 +294,11 @@ class AIAgent:
#5) some topic could be end(not be thinked in futured )
return
async def think_chatsession(self,session_id):
if self.agent_think_prompt is None:
return
logger.info(f"agent {self.agent_id} think session {session_id}")
from .compute_kernel import ComputeKernel
chatsession = AIChatSession.get_session_by_id(session_id,self.chat_db)
while True:
@@ -421,9 +330,6 @@ class AIAgent:
return
async def _process_group_chat_msg(self,msg:AgentMsg) -> AgentMsg:
from .compute_kernel import ComputeKernel
from .bus import AIBus
session_topic = msg.target + "#" + msg.topic
chatsession = AIChatSession.get_session(self.agent_id,session_topic,self.chat_db)
need_process = False
@@ -453,26 +359,13 @@ class AIAgent:
prompt.append(msg_prompt)
logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
task_result = await self._do_llm_complection(prompt,inner_functions,msg)
if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"llm compute error:{task_result.error_str}")
error_resp = msg.create_error_resp(task_result.error_str)
return error_resp
final_result = task_result.result_str
result_message = task_result.result.get("message")
if result_message:
inner_func_call_node = result_message.get("function_call")
if inner_func_call_node:
#TODO to save more token ,can i use msg_prompt?
call_prompt : AgentPrompt = copy.deepcopy(prompt)
final_result,error_code = await self._execute_func(inner_func_call_node,call_prompt,msg)
if error_code != 0:
error_resp = msg.create_error_resp(final_result)
return error_resp
llm_result : LLMResult = self._get_llm_result_type(final_result)
llm_result : LLMResult = LLMResult.from_str(final_result)
is_ignore = False
result_prompt_str = ""
match llm_result.state:
@@ -481,6 +374,7 @@ class AIAgent:
case "waiting":
for sendmsg in llm_result.send_msgs:
target = sendmsg.target
sendmsg.sender = self.agent_id
sendmsg.topic = msg.topic
sendmsg.prev_msg_id = msg.get_msg_id()
send_resp = await AIBus.get_default_bus().send_message(sendmsg)
@@ -502,16 +396,12 @@ class AIAgent:
return None
async def _process_msg(self,msg:AgentMsg) -> AgentMsg:
from .compute_kernel import ComputeKernel
from .bus import AIBus
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
return await self._process_group_chat_msg(msg)
session_topic = msg.get_sender() + "#" + msg.topic
chatsession = AIChatSession.get_session(self.agent_id,session_topic,self.chat_db)
msg_prompt = AgentPrompt()
msg_prompt.messages = [{"role":"user","content":msg.body}]
@@ -530,26 +420,15 @@ class AIAgent:
prompt.append(msg_prompt)
logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
#task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
task_result = await self._do_llm_complection(prompt,inner_functions,msg)
if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"llm compute error:{task_result.error_str}")
error_resp = msg.create_error_resp(task_result.error_str)
return error_resp
final_result = task_result.result_str
result_message = task_result.result.get("message")
if result_message:
inner_func_call_node = result_message.get("function_call")
if inner_func_call_node:
#TODO to save more token ,can i use msg_prompt?
call_prompt : AgentPrompt = copy.deepcopy(prompt)
final_result,error_code = await self._execute_func(inner_func_call_node,call_prompt,msg)
if error_code != 0:
error_resp = msg.create_error_resp(final_result)
return error_resp
llm_result : LLMResult = self._get_llm_result_type(final_result)
llm_result : LLMResult = LLMResult.from_str(final_result)
is_ignore = False
result_prompt_str = ""
match llm_result.state:
@@ -557,6 +436,7 @@ class AIAgent:
is_ignore = True
case "waiting":
for sendmsg in llm_result.send_msgs:
sendmsg.sender = self.agent_id
target = sendmsg.target
sendmsg.topic = msg.topic
sendmsg.prev_msg_id = msg.get_msg_id()
@@ -578,20 +458,7 @@ class AIAgent:
return None
def get_id(self) -> str:
return self.agent_id
def get_fullname(self) -> str:
return self.fullname
def get_template_id(self) -> str:
return self.template_id
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_history_prompt_for_think(self,chatsession:AIChatSession,summary:str,system_token_len:int,pos:int)->(AgentPrompt,int):
history_len = (self.max_token_size * 0.7) - system_token_len
@@ -660,6 +527,74 @@ class AIAgent:
return result_prompt,result_token_len
async def _do_llm_complection(self,prompt:AgentPrompt,inner_functions:dict,org_msg:AgentMsg=None) -> ComputeTaskResult:
from .compute_kernel import ComputeKernel
#logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"llm compute error:{task_result.error_str}")
#error_resp = msg.create_error_resp(task_result.error_str)
return task_result
result_message = task_result.result.get("message")
inner_func_call_node = None
if result_message:
inner_func_call_node = result_message.get("function_call")
if inner_func_call_node:
call_prompt : AgentPrompt = copy.deepcopy(prompt)
task_result = await self._execute_func(inner_func_call_node,call_prompt,inner_functions,org_msg)
return task_result
def parser_learn_llm_result(self,llm_result:str):
pass
async def _llm_read_article(self,kb:KnowledgeBase,item:KnowledgeObject) -> ComputeTaskResult:
#kb_env = KnowledgeBaseFileSystemEnvironment()
full_content = item.get_article_full_content()
full_content_len = ComputeKernel.llm_num_tokens_from_text(full_content,self.get_llm_model_name())
if full_content_len < self.get_llm_learn_token_limit():
# 短文章不用总结catelog
#path_list,summary = llm_get_summary(summary,full_content)
prompt = self.get_agent_role_prompt()
learn_prompt = self.get_learn_prompt()
cotent_prompt = AgentPrompt(full_content)
prompt.append(learn_prompt)
prompt.append(cotent_prompt)
env_functions = self._get_inner_functions()
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,env_functions)
if task_result.result_code != ComputeTaskResultCode.OK:
return task_result
path_list,summary = self.parser_learn_llm_result(task_result.result_str)
else:
# 用传统方法对文章进行一些处理,目的是尽可能减少LLM调用的次数
catelog = item.get_articl_catelog()
chunk_content = full_content.read(self.get_llm_learn_token_limit())
summary = kb.try_get_summary(catelog,full_content)
while chunk_content is not None:
#path_list,summarycatelog = llm_get_summary(summary,chunk_content)
#learn_prompt = self.get_learn_prompt_with_summary()
prompt = AgentPrompt("summary")
learn_prompt.append(prompt)
prompt = AgentPrompt(chunk_content)
learn_prompt.append(prompt)
#llm_result = self.do_llm_competion(learn_prompt)
#path_list,summary,catelog = parser_learn_llm_result(llm_result)
#chunk_content = full_content.read(self.get_llm_learn_token_limit())
kb.insert_item(path_list,item,catelog,summary)
async def _get_prompt_from_session(self,chatsession:AIChatSession,system_token_len,input_token_len) -> AgentPrompt:
# TODO: get prompt from group chat is different from single chat
+317
View File
@@ -0,0 +1,317 @@
import copy
import logging
from enum import Enum
import uuid
import time
import re
import shlex
from typing import List
from .ai_function import FunctionItem
logger = logging.getLogger(__name__)
class AgentMsgType(Enum):
TYPE_MSG = 0
TYPE_GROUPMSG = 1
TYPE_INTERNAL_CALL = 10
TYPE_ACTION = 20
TYPE_EVENT = 30
TYPE_SYSTEM = 40
class AgentMsgStatus(Enum):
RESPONSED = 0
INIT = 1
SENDING = 2
PROCESSING = 3
ERROR = 4
RECVED = 5
EXECUTED = 6
# msg is a msg / msg resp
# msg body可以有内容类型(MIME标签),text, image, voice, video, file,以及富文本(html)
# msg is a inner function call with result
# msg is a Action with result
# qutoe Msg
# forword msg
# reply msg
# 逻辑上的同一个Message在同一个session中看到的msgid相同
# 在不同的session中看到的msgid不同
class AgentMsg:
def __init__(self,msg_type=AgentMsgType.TYPE_MSG) -> None:
self.msg_id = "msg#" + uuid.uuid4().hex
self.msg_type:AgentMsgType = msg_type
self.prev_msg_id:str = None
self.quote_msg_id:str = None
self.rely_msg_id:str = None # if not none means this is a respone msg
self.session_id:str = None
#forword info
self.create_time = 0
self.done_time = 0
self.topic:str = None # topic is use to find session, not store in db
self.sender:str = None # obj_id.sub_objid@tunnel_id
self.target:str = None
self.mentions:[] = None #use in group chat only
#self.title:str = None
self.body:str = None
self.body_mime:str = None #//default is "text/plain",encode is utf8
#type is call / action
self.func_name = None
self.args = None
self.result_str = None
#type is event
self.event_name = None
self.event_args = None
self.status = AgentMsgStatus.INIT
self.inner_call_chain = []
self.resp_msg = None
@classmethod
def create_internal_call_msg(self,func_name:str,args:dict,prev_msg_id:str,caller:str):
msg = AgentMsg(AgentMsgType.TYPE_INTERNAL_CALL)
msg.create_time = time.time()
msg.func_name = func_name
msg.args = args
msg.prev_msg_id = prev_msg_id
msg.sender = caller
return msg
def create_action_msg(self,action_name:str,args:dict,caller:str):
msg = AgentMsg(AgentMsgType.TYPE_ACTION)
msg.create_time = time.time()
msg.func_name = action_name
msg.args = args
msg.prev_msg_id = self.msg_id
msg.topic = self.topic
msg.sender = caller
return msg
def create_error_resp(self,error_msg:str):
resp_msg = AgentMsg(AgentMsgType.TYPE_SYSTEM)
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.body = error_msg
resp_msg.topic = self.topic
resp_msg.sender = self.target
resp_msg.target = self.sender
return resp_msg
def create_resp_msg(self,resp_body):
resp_msg = AgentMsg()
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.sender = self.target
resp_msg.target = self.sender
resp_msg.body = resp_body
resp_msg.topic = self.topic
return resp_msg
def create_group_resp_msg(self,sender_id,resp_body):
resp_msg = AgentMsg(AgentMsgType.TYPE_GROUPMSG)
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.target = self.target
resp_msg.sender = sender_id
resp_msg.body = resp_body
resp_msg.topic = self.topic
return resp_msg
def set(self,sender:str,target:str,body:str,topic:str=None) -> None:
self.sender = sender
self.target = target
self.body = body
self.create_time = time.time()
if topic:
self.topic = topic
def get_msg_id(self) -> str:
return self.msg_id
def get_sender(self) -> str:
return self.sender
def get_target(self) -> str:
return self.target
def get_prev_msg_id(self) -> str:
return self.prev_msg_id
def get_quote_msg_id(self) -> str:
return self.quote_msg_id
@classmethod
def parse_function_call(cls,func_string:str):
str_list = shlex.split(func_string)
func_name = str_list[0]
params = str_list[1:]
return func_name, params
class AgentPrompt:
def __init__(self,prompt_str = None) -> None:
self.messages = []
if prompt_str:
self.messages.append({"role":"user","content":prompt_str})
self.system_message = None
def as_str(self)->str:
result_str = ""
if self.system_message:
result_str += self.system_message.get("role") + ":" + self.system_message.get("content") + "\n"
if self.messages:
for msg in self.messages:
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 = copy.deepcopy(prompt.system_message)
else:
self.system_message["content"] += prompt.system_message.get("content")
self.messages.extend(prompt.messages)
def get_prompt_token_len(self):
result = 0
if self.system_message:
result += len(self.system_message.get("content"))
for msg in self.messages:
result += len(msg.get("content"))
return result
def load_from_config(self,config:list) -> bool:
if isinstance(config,list) is not True:
logger.error("prompt is not list!")
return False
self.messages = []
for msg in config:
if msg.get("role") == "system":
self.system_message = msg
else:
self.messages.append(msg)
return True
class LLMResult:
def __init__(self) -> None:
self.state : str = "ignore"
self.resp : str = ""
self.paragraphs : dict[str,FunctionItem] = []
self.post_msgs : List[AgentMsg] = []
self.send_msgs : List[AgentMsg] = []
self.calls : List[FunctionItem] = []
self.post_calls : List[FunctionItem] = []
@classmethod
def from_str(self,llm_result_str:str,valid_func:List[str]=None) -> '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
def check_args(func_item:FunctionItem):
match func_name:
case "send_msg":# /send_msg $target_id
if len(func_args) != 1:
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
msg_content = func_item.body
new_msg.set("",target_id,msg_content)
r.send_msgs.append(new_msg)
is_need_wait = True
return True
case "post_msg":# /post_msg $target_id
if len(func_args) != 1:
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
msg_content = func_item.body
new_msg.set("",target_id,msg_content)
r.post_msgs.append(new_msg)
return True
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
case _:
if valid_func is not None:
if func_name in valid_func:
r.paragraphs[func_name] = func_item
return True
return False
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:
if current_func:
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:
r.state = "reponsed"
return r
class BaseAIAgent:
def __init__(self) -> None:
pass
-169
View File
@@ -1,169 +0,0 @@
from enum import Enum
import uuid
import time
import re
import shlex
from typing import List
from .ai_function import FunctionItem
class AgentMsgType(Enum):
TYPE_MSG = 0
TYPE_GROUPMSG = 1
TYPE_INTERNAL_CALL = 10
TYPE_ACTION = 20
TYPE_EVENT = 30
TYPE_SYSTEM = 40
class AgentMsgStatus(Enum):
RESPONSED = 0
INIT = 1
SENDING = 2
PROCESSING = 3
ERROR = 4
RECVED = 5
EXECUTED = 6
# msg is a msg / msg resp
# msg body可以有内容类型(MIME标签),text, image, voice, video, file,以及富文本(html)
# msg is a inner function call with result
# msg is a Action with result
# qutoe Msg
# forword msg
# reply msg
# 逻辑上的同一个Message在同一个session中看到的msgid相同
# 在不同的session中看到的msgid不同
class AgentMsg:
def __init__(self,msg_type=AgentMsgType.TYPE_MSG) -> None:
self.msg_id = "msg#" + uuid.uuid4().hex
self.msg_type:AgentMsgType = msg_type
self.prev_msg_id:str = None
self.quote_msg_id:str = None
self.rely_msg_id:str = None # if not none means this is a respone msg
self.session_id:str = None
#forword info
self.create_time = 0
self.done_time = 0
self.topic:str = None # topic is use to find session, not store in db
self.sender:str = None # obj_id.sub_objid@tunnel_id
self.target:str = None
self.mentions:[] = None #use in group chat only
#self.title:str = None
self.body:str = None
self.body_mime:str = None #//default is "text/plain",encode is utf8
#type is call / action
self.func_name = None
self.args = None
self.result_str = None
#type is event
self.event_name = None
self.event_args = None
self.status = AgentMsgStatus.INIT
self.inner_call_chain = []
self.resp_msg = None
@classmethod
def create_internal_call_msg(self,func_name:str,args:dict,prev_msg_id:str,caller:str):
msg = AgentMsg(AgentMsgType.TYPE_INTERNAL_CALL)
msg.create_time = time.time()
msg.func_name = func_name
msg.args = args
msg.prev_msg_id = prev_msg_id
msg.sender = caller
return msg
def create_action_msg(self,action_name:str,args:dict,caller:str):
msg = AgentMsg(AgentMsgType.TYPE_ACTION)
msg.create_time = time.time()
msg.func_name = action_name
msg.args = args
msg.prev_msg_id = self.msg_id
msg.topic = self.topic
msg.sender = caller
return msg
def create_error_resp(self,error_msg:str):
resp_msg = AgentMsg(AgentMsgType.TYPE_SYSTEM)
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.body = error_msg
resp_msg.topic = self.topic
resp_msg.sender = self.target
resp_msg.target = self.sender
return resp_msg
def create_resp_msg(self,resp_body):
resp_msg = AgentMsg()
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.sender = self.target
resp_msg.target = self.sender
resp_msg.body = resp_body
resp_msg.topic = self.topic
return resp_msg
def create_group_resp_msg(self,sender_id,resp_body):
resp_msg = AgentMsg(AgentMsgType.TYPE_GROUPMSG)
resp_msg.create_time = time.time()
resp_msg.rely_msg_id = self.msg_id
resp_msg.target = self.target
resp_msg.sender = sender_id
resp_msg.body = resp_body
resp_msg.topic = self.topic
return resp_msg
def set(self,sender:str,target:str,body:str,topic:str=None) -> None:
self.sender = sender
self.target = target
self.body = body
self.create_time = time.time()
if topic:
self.topic = topic
def get_msg_id(self) -> str:
return self.msg_id
def get_sender(self) -> str:
return self.sender
def get_target(self) -> str:
return self.target
def get_prev_msg_id(self) -> str:
return self.prev_msg_id
def get_quote_msg_id(self) -> str:
return self.quote_msg_id
@classmethod
def parse_function_call(cls,func_string:str):
str_list = shlex.split(func_string)
func_name = str_list[0]
params = str_list[1:]
return func_name, params
class LLMResult:
def __init__(self) -> None:
self.state : str = "ignore"
self.resp : str = ""
self.post_msgs : List[AgentMsg] = []
self.send_msgs : List[AgentMsg] = []
self.calls : List[FunctionItem] = []
self.post_calls : List[FunctionItem] = []
+1 -1
View File
@@ -1,5 +1,5 @@
from typing import Coroutine,Dict,Any
from .agent_message import AgentMsg,AgentMsgStatus,AgentMsgType
from .agent_base import AgentMsg,AgentMsgStatus,AgentMsgType
import asyncio
from asyncio import Queue
+1 -1
View File
@@ -7,7 +7,7 @@ import datetime
import uuid
import json
from .agent_message import AgentMsgType, AgentMsg, AgentMsgStatus
from .agent_base import AgentMsgType, AgentMsg, AgentMsgStatus
class ChatSessionDB:
def __init__(self, db_file):
+15 -1
View File
@@ -3,10 +3,12 @@ import random
from typing import Optional
import logging
import asyncio
import tiktoken
from asyncio import Queue
from knowledge import ObjectID
from .agent import AgentPrompt
from .agent_base import AgentPrompt
from .compute_node import ComputeNode
from .compute_task import ComputeTask, ComputeTaskState, ComputeTaskResult, ComputeTaskType,ComputeTaskResultCode
@@ -104,6 +106,18 @@ class ComputeKernel:
def is_task_support(self, task: ComputeTask) -> bool:
return True
@staticmethod
def llm_num_tokens_from_text(text:str,model:str) -> int:
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
logger.debug("Warning: model not found. Using cl100k_base encoding.")
encoding = tiktoken.get_encoding("cl100k_base")
token_count = len(encoding.encode(text))
return token_count
# friendly interface for use:
def llm_completion(self, prompt: AgentPrompt, mode_name: Optional[str] = None, max_token: int = 0,inner_functions = None):
# craete a llm_work_task ,push on queue's end
+1 -1
View File
@@ -8,7 +8,7 @@ import logging
import time
import datetime
from .tunnel import AgentTunnel
from .agent_message import AgentMsg
from .agent_base import AgentMsg
from email.message import EmailMessage
+2 -1
View File
@@ -1,7 +1,8 @@
# define a knowledge base class
import json
import logging
from .agent import AgentPrompt
from .agent_base import AgentPrompt
from .compute_kernel import ComputeKernel
from .storage import AIStorage
from .environment import Environment
+1 -1
View File
@@ -118,7 +118,7 @@ class OpenAI_ComputeNode(ComputeNode):
#max_tokens=result_token,
temperature=0.7)
else:
logger.info(f"call openai {mode_name} prompts: {prompts} functions: {json.dumps(llm_inner_functions)}")
logger.info(f"call openai {mode_name} prompts: \n\t {prompts} \nfunctions: \n\t{json.dumps(llm_inner_functions)}")
resp = openai.ChatCompletion.create(model=mode_name,
messages=prompts,
functions=llm_inner_functions,
+1 -1
View File
@@ -1,6 +1,6 @@
import logging
from .agent import AIAgent,AgentPrompt
from .agent_base import AgentPrompt
class AIRole:
def __init__(self) -> None:
+1 -1
View File
@@ -17,7 +17,7 @@ from .knowledge_base import KnowledgeBase
from .tunnel import AgentTunnel
from .storage import AIStorage
from .contact_manager import ContactManager,Contact,FamilyMember
from .agent_message import AgentMsg,AgentMsgType
from .agent_base import AgentMsg,AgentMsgType
logger = logging.getLogger(__name__)
+1 -1
View File
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
import logging
from typing import Coroutine
from .agent_message import AgentMsg
from .agent_base import AgentMsg
from .bus import AIBus
logger = logging.getLogger(__name__)
+2 -76
View File
@@ -8,8 +8,7 @@ from typing import Optional,Tuple,List
from abc import ABC, abstractmethod
from .environment import Environment,EnvironmentEvent
from .agent_message import AgentMsg,AgentMsgStatus,FunctionItem,LLMResult
from .agent import AgentPrompt,AgentMsg
from .agent_base import AgentMsg,AgentMsgStatus,FunctionItem,LLMResult,AgentPrompt
from .chatsession import AIChatSession
from .role import AIRole,AIRoleGroup
from .ai_function import AIFunction,FunctionItem
@@ -238,77 +237,6 @@ class Workflow:
error_resp = msg.create_error_resp(err_str)
return error_resp
@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
def check_args(func_item:FunctionItem):
match func_name:
case "send_msg":# sendmsg($target_id,$msg_content)
if len(func_item.args) != 1:
logger.error(f"parse sendmsg failed! {func_item}")
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
msg_content = func_item.body
new_msg.set("_",target_id,msg_content)
r.send_msgs.append(new_msg)
is_need_wait = True
case "post_msg":# postmsg($target_id,$msg_content)
if len(func_item.args) != 1:
logger.error(f"parse postmsg failed! {func_item}")
return False
new_msg = AgentMsg()
target_id = func_item.args[0]
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
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:
if current_func:
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:
r.state = "reponsed"
return r
async def role_post_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession):
msg.sender = the_role.get_role_id()
@@ -395,7 +323,6 @@ class Workflow:
return None
async def _role_execute_func(self,the_role:AIRole,inenr_func_call_node:dict,prompt:AgentPrompt,org_msg:AgentMsg,stack_limit = 5) -> [str,int]:
from .compute_kernel import ComputeKernel
func_name = inenr_func_call_node.get("name")
arguments = json.loads(inenr_func_call_node.get("arguments"))
@@ -441,7 +368,6 @@ class Workflow:
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession) -> AgentMsg:
msg.target = the_role.get_role_id()
prompt = AgentPrompt()
prompt.append(the_role.agent.agent_prompt)
prompt.append(self.get_workflow_rule_prompt())
@@ -481,7 +407,7 @@ class Workflow:
error_resp = msg.create_error_resp(result_str)
return error_resp
result : LLMResult = Workflow.prase_llm_result(result_str)
result : LLMResult = LLMResult.from_str(result_str)
for postmsg in result.post_msgs:
postmsg.prev_msg_id = msg.get_msg_id()
# might be craete a new msg.topic for this postmsg
+50
View File
@@ -1,5 +1,6 @@
# this env is designed for workflow owner filesystem, support file/directory operations
import json
import subprocess
import tempfile
import threading
@@ -9,6 +10,9 @@ import ast
import sys
import os
import re
import asyncio
import aiofiles.os
import chardet
from .environment import Environment,EnvironmentEvent
from .ai_function import AIFunction,SimpleAIFunction
@@ -171,3 +175,49 @@ class WorkspaceEnvironment(Environment):
interpreter = CodeInterpreter("python",True)
return interpreter.run(pycode)
class KnowledgeBaseFileSystemEnvironment(Environment):
def __init__(self, env_id: str) -> None:
super().__init__(env_id)
self.root_path = "."
operator_param = {
"path": "full path of target directory",
}
self.add_ai_function(SimpleAIFunction("list",
"list the files and sub directory in target directory,result is a json array",
self.list,operator_param))
operator_param = {
"path": "full path of target file",
}
self.add_ai_function(SimpleAIFunction("cat",
"cat the file content in target path,result is a string",
self.cat,operator_param))
def set_root_path(self,path:str):
self.root_path = path
async def list(self,path:str) -> str:
directory_path = self.root_path + path
items = []
with await aiofiles.os.scandir(directory_path) as entries:
async for entry in entries:
item_type = "directory" if entry.is_dir() else "file"
items.append({"name": entry.name, "type": item_type})
return json.dumps(items)
async def cat(self,path:str) -> str:
file_path = self.root_path + path
cur_encode = "utf-8"
async with aiofiles.open(file_path,'rb') as f:
cur_encode = chardet.detect(await f.read())['encoding']
async with aiofiles.open(file_path, mode='r', encoding=cur_encode) as f:
content = await f.read(2048)
return content
+11
View File
@@ -48,6 +48,17 @@ class KnowledgeObject(ABC):
def get_body(self) -> dict:
return self.body
def get_summary(self) -> str:
return self.desc.get("summary")
def get_articl_catelog(self) -> str:
assert self.object_type == ObjectType.Document
return self.desc.get("catelog")
def get_article_full_content(self) -> str:
assert self.object_type == ObjectType.Document
return self.body
def calculate_id(self):
# Convert the object_type and desc to string and compute the SHA256 hash
data = json.dumps(
+4
View File
@@ -6,6 +6,8 @@ from .vector import ChromaVectorStore, VectorBase
import logging
# KnowledgeStore class, which aggregates ChunkStore, ChunkTracker, and ObjectStore, and is a global singleton that makes it easy to use these three built-in store examples
class KnowledgeStore:
_instance = None
@@ -42,6 +44,8 @@ class KnowledgeStore:
self.chunk_reader = ChunkReader(self.chunk_store, self.chunk_tracker)
self.vector_store = {}
def get_relation_store(self) -> ObjectRelationStore:
return self.relation_store