rollback agent memory to "chat session history & session summary"
This commit is contained in:
@@ -248,14 +248,11 @@ class AIAgent(BaseAIAgent):
|
||||
logger.info(f"agent {self.agent_id} self thinking start!")
|
||||
|
||||
context_info = await self._get_context_info()
|
||||
known_session_list = AIChatSession.list_session(self.agent_id,self.memory.memory_db)
|
||||
known_experience_list = await self.memory.list_experience()
|
||||
record_list = await self.memory.load_records(await self.memory.get_last_think_time())
|
||||
#chat_history = AIChatSession.list_session(self.agent_id,self.memory.memory_db)
|
||||
#known_experience_list = await self.memory.list_experience()
|
||||
#record_list = await self.memory.load_records(await self.memory.get_last_think_time())
|
||||
|
||||
input_parms = {
|
||||
"record_list":record_list,
|
||||
"known_session_list":known_session_list,
|
||||
"known_experience_list":known_experience_list,
|
||||
"context_info":context_info
|
||||
}
|
||||
|
||||
@@ -266,7 +263,7 @@ class AIAgent(BaseAIAgent):
|
||||
logger.info(f"llm process self thinking ignore!")
|
||||
else:
|
||||
logger.info(f"llm process self thinking ok!,think is:{llm_result.resp}")
|
||||
self.memory.set_last_think_time(time.time())
|
||||
await self.memory.set_last_think_time(time.time())
|
||||
self.agent_energy -= 2
|
||||
return
|
||||
|
||||
|
||||
+148
-150
@@ -92,49 +92,31 @@ class AgentMemory:
|
||||
work_records = self.load_worklogs(self.agent_id,token_limit=tokenlimit)
|
||||
pass
|
||||
|
||||
async def load_chatlogs(self,msg:AgentMsg,n:int=6,m:int=64,token_limit=800)->str:
|
||||
async def load_chatlogs(self,msg:AgentMsg,token_limit=800):
|
||||
chatsession = self.get_session_from_msg(msg)
|
||||
# Must load n (n> = 2), and hope to load the M
|
||||
# The information in the # M is gradually added, knowing that it is less than 72 hours from the current time, and consumes enough tokens
|
||||
|
||||
messages_n = chatsession.read_history(n) # read
|
||||
if len(messages_n) >= n:
|
||||
messages_m = chatsession.read_history(m,n)
|
||||
else:
|
||||
messages_m = []
|
||||
|
||||
messages_n = chatsession.read_history() # read
|
||||
histroy_str = ""
|
||||
read_count = 0
|
||||
is_all = True
|
||||
for msg in messages_n:
|
||||
dt = datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
token_limit -= ComputeKernel.llm_num_tokens_from_text(record_str,self.model_name)
|
||||
if token_limit <= 32:
|
||||
is_all = False
|
||||
break
|
||||
read_count += 1
|
||||
histroy_str = record_str + histroy_str
|
||||
|
||||
if len(messages_n) > 2:
|
||||
if read_count < 3:
|
||||
logging.warning(f"read history {read_count} < 3, will not load more")
|
||||
|
||||
now = datetime.now()
|
||||
for msg in messages_m:
|
||||
dt = datetime.fromtimestamp(float(msg.create_time))
|
||||
time_diff = now - dt
|
||||
if time_diff > timedelta(hours=self.threshold_hours):
|
||||
break
|
||||
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
token_limit -= ComputeKernel.llm_num_tokens_from_text(record_str,self.model_name)
|
||||
if token_limit <= 32:
|
||||
break
|
||||
read_count += 1
|
||||
histroy_str = record_str + histroy_str
|
||||
|
||||
return histroy_str
|
||||
return histroy_str,is_all
|
||||
|
||||
async def get_chat_summary(self,msg:AgentMsg) -> str:
|
||||
chatsession : AIChatSession = self.get_session_from_msg(msg)
|
||||
return chatsession.summary
|
||||
|
||||
# async def action_chatlog_append(self,params:Dict) -> str:
|
||||
#
|
||||
@@ -293,7 +275,7 @@ class AgentMemory:
|
||||
try:
|
||||
async with aiofiles.open(summary_path, mode='w') as file:
|
||||
await file.write(summary)
|
||||
return "OK"
|
||||
return "OK"
|
||||
except Exception as e:
|
||||
logger.error(f"write summary failed: {e}")
|
||||
return f"write summary failed: {e}"
|
||||
@@ -363,141 +345,157 @@ class AgentMemory:
|
||||
|
||||
@staticmethod
|
||||
def register_ai_functions():
|
||||
async def get_contact_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
contact_name = parameters.get("contact_name")
|
||||
return await agent_memory.get_contact_summary(contact_name)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"contact_name": {"type": "string", "description": "contact name"}
|
||||
})
|
||||
get_contact_summary_func = SimpleAIFunction("agent.memory.get_contact_summary",
|
||||
"get contact summary",
|
||||
get_contact_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(get_contact_summary_func)
|
||||
|
||||
async def update_contact_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
contact_name = parameters.get("contact_name")
|
||||
async def update_chat_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_memory")
|
||||
chatsession = AIChatSession.get_session_by_id(parameters.get("session_id"),agent_memory.memory_db)
|
||||
summary = parameters.get("summary")
|
||||
return await agent_memory.update_contact_summary(contact_name,summary)
|
||||
chatsession.update_summary(summary)
|
||||
return "OK"
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"contact_name": {"type": "string", "description": "contact name"},
|
||||
"session_id": {"type": "string", "description": "session id"},
|
||||
"summary": {"type": "string", "description": "new summary"}
|
||||
})
|
||||
update_contact_summary_func = SimpleAIFunction("agent.memory.update_contact_summary",
|
||||
"update contact summary",
|
||||
update_contact_summary,
|
||||
update_chat_summary_func = SimpleAIFunction("agent.memory.update_chat_summary",
|
||||
"update chat summary",
|
||||
update_chat_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(update_contact_summary_func)
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(update_chat_summary_func)
|
||||
|
||||
async def get_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
object_name = parameters.get("object_name")
|
||||
return await agent_memory.get_summary(object_name)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"object_name": {"type": "string", "description": "object name"}
|
||||
})
|
||||
get_summary_func = SimpleAIFunction("agent.memory.get_summary",
|
||||
"get summary of sth",
|
||||
get_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(get_summary_func)
|
||||
# async def get_contact_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# contact_name = parameters.get("contact_name")
|
||||
# return await agent_memory.get_contact_summary(contact_name)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "contact_name": {"type": "string", "description": "contact name"}
|
||||
# })
|
||||
# get_contact_summary_func = SimpleAIFunction("agent.memory.get_contact_summary",
|
||||
# "get contact summary",
|
||||
# get_contact_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(get_contact_summary_func)
|
||||
|
||||
async def update_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
object_name = parameters.get("object_name")
|
||||
summary = parameters.get("summary")
|
||||
return await agent_memory.update_summary(object_name,summary)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"object_name": {"type": "string", "description": "object name"},
|
||||
"summary": {"type": "string", "description": "new summary"}
|
||||
})
|
||||
update_summary_func = SimpleAIFunction("agent.memory.update_summary",
|
||||
"update summary of sth",
|
||||
update_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(update_summary_func)
|
||||
# async def update_contact_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# contact_name = parameters.get("contact_name")
|
||||
# summary = parameters.get("summary")
|
||||
# return await agent_memory.update_contact_summary(contact_name,summary)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "contact_name": {"type": "string", "description": "contact name"},
|
||||
# "summary": {"type": "string", "description": "new summary"}
|
||||
# })
|
||||
# update_contact_summary_func = SimpleAIFunction("agent.memory.update_contact_summary",
|
||||
# "update contact summary",
|
||||
# update_contact_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(update_contact_summary_func)
|
||||
|
||||
async def list_summary_object_names(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
return await agent_memory.list_summary_object_names()
|
||||
parameters = ParameterDefine.create_parameters({})
|
||||
list_summary_object_names_func = SimpleAIFunction("agent.memory.list_summary",
|
||||
"list summary object names",
|
||||
list_summary_object_names,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(list_summary_object_names_func)
|
||||
# async def get_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# object_name = parameters.get("object_name")
|
||||
# return await agent_memory.get_summary(object_name)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "object_name": {"type": "string", "description": "object name"}
|
||||
# })
|
||||
# get_summary_func = SimpleAIFunction("agent.memory.get_summary",
|
||||
# "get summary of sth",
|
||||
# get_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(get_summary_func)
|
||||
|
||||
async def get_relation_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
object_name1 = parameters.get("object1_name")
|
||||
object_name2 = parameters.get("object2_name")
|
||||
return await agent_memory.get_relation_summary(object_name1,object_name2)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"object1_name": {"type": "string", "description": "object name1"},
|
||||
"object2_name": {"type": "string", "description": "object name2"}
|
||||
})
|
||||
get_relation_summary_func = SimpleAIFunction("agent.memory.get_relation_summary",
|
||||
"object1 feel object2 is ...",
|
||||
get_relation_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(get_relation_summary_func)
|
||||
# async def update_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# object_name = parameters.get("object_name")
|
||||
# summary = parameters.get("summary")
|
||||
# return await agent_memory.update_summary(object_name,summary)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "object_name": {"type": "string", "description": "object name"},
|
||||
# "summary": {"type": "string", "description": "new summary"}
|
||||
# })
|
||||
# update_summary_func = SimpleAIFunction("agent.memory.update_summary",
|
||||
# "update summary of sth",
|
||||
# update_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(update_summary_func)
|
||||
|
||||
async def update_relation_summary(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
object_name1 = parameters.get("object1_name")
|
||||
object_name2 = parameters.get("object2_name")
|
||||
summary = parameters.get("summary")
|
||||
return await agent_memory.update_relation_summary(object_name1,object_name2,summary)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"object1_name": {"type": "string", "description": "object name1"},
|
||||
"object2_name": {"type": "string", "description": "object name2"},
|
||||
"summary": {"type": "string", "description": "new summary"}
|
||||
})
|
||||
update_relation_summary_func = SimpleAIFunction("agent.memory.update_relation_summary",
|
||||
"object1 feel object2 is ...",
|
||||
update_relation_summary,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(update_relation_summary_func)
|
||||
# async def list_summary_object_names(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# return await agent_memory.list_summary_object_names()
|
||||
# parameters = ParameterDefine.create_parameters({})
|
||||
# list_summary_object_names_func = SimpleAIFunction("agent.memory.list_summary",
|
||||
# "list summary object names",
|
||||
# list_summary_object_names,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(list_summary_object_names_func)
|
||||
|
||||
async def get_experience(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
topic_name = parameters.get("topic_name")
|
||||
return await agent_memory.get_experience(topic_name)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"topic_name": {"type": "string", "description": "topic name"}
|
||||
})
|
||||
get_experience_func = SimpleAIFunction("agent.memory.get_experience",
|
||||
"get experience",
|
||||
get_experience,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(get_experience_func)
|
||||
# async def get_relation_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# object_name1 = parameters.get("object1_name")
|
||||
# object_name2 = parameters.get("object2_name")
|
||||
# return await agent_memory.get_relation_summary(object_name1,object_name2)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "object1_name": {"type": "string", "description": "object name1"},
|
||||
# "object2_name": {"type": "string", "description": "object name2"}
|
||||
# })
|
||||
# get_relation_summary_func = SimpleAIFunction("agent.memory.get_relation_summary",
|
||||
# "object1 feel object2 is ...",
|
||||
# get_relation_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(get_relation_summary_func)
|
||||
|
||||
async def set_experience(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
topic_name = parameters.get("topic_name")
|
||||
summary = parameters.get("summary")
|
||||
return await agent_memory.set_experience(topic_name,summary)
|
||||
parameters = ParameterDefine.create_parameters({
|
||||
"topic_name": {"type": "string", "description": "topic name"},
|
||||
"summary": {"type": "string", "description": "new summary"}
|
||||
})
|
||||
set_experience_func = SimpleAIFunction("agent.memory.set_experience",
|
||||
"set experience",
|
||||
set_experience,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(set_experience_func)
|
||||
# async def update_relation_summary(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# object_name1 = parameters.get("object1_name")
|
||||
# object_name2 = parameters.get("object2_name")
|
||||
# summary = parameters.get("summary")
|
||||
# return await agent_memory.update_relation_summary(object_name1,object_name2,summary)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "object1_name": {"type": "string", "description": "object name1"},
|
||||
# "object2_name": {"type": "string", "description": "object name2"},
|
||||
# "summary": {"type": "string", "description": "new summary"}
|
||||
# })
|
||||
# update_relation_summary_func = SimpleAIFunction("agent.memory.update_relation_summary",
|
||||
# "object1 feel object2 is ...",
|
||||
# update_relation_summary,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(update_relation_summary_func)
|
||||
|
||||
async def list_experience(parameters):
|
||||
agent_memory:AgentMemory = parameters.get("_agent_memory")
|
||||
return await agent_memory.list_experience()
|
||||
parameters = ParameterDefine.create_parameters({})
|
||||
list_experience_func = SimpleAIFunction("agent.memory.list_experience",
|
||||
"list exist experience topics",
|
||||
list_experience,
|
||||
parameters)
|
||||
GlobaToolsLibrary.register_tool_function(list_experience_func)
|
||||
# async def get_experience(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# topic_name = parameters.get("topic_name")
|
||||
# return await agent_memory.get_experience(topic_name)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "topic_name": {"type": "string", "description": "topic name"}
|
||||
# })
|
||||
# get_experience_func = SimpleAIFunction("agent.memory.get_experience",
|
||||
# "get experience",
|
||||
# get_experience,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(get_experience_func)
|
||||
|
||||
# async def set_experience(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# topic_name = parameters.get("topic_name")
|
||||
# summary = parameters.get("summary")
|
||||
# return await agent_memory.set_experience(topic_name,summary)
|
||||
# parameters = ParameterDefine.create_parameters({
|
||||
# "topic_name": {"type": "string", "description": "topic name"},
|
||||
# "summary": {"type": "string", "description": "new summary"}
|
||||
# })
|
||||
# set_experience_func = SimpleAIFunction("agent.memory.set_experience",
|
||||
# "set experience",
|
||||
# set_experience,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(set_experience_func)
|
||||
|
||||
# async def list_experience(parameters):
|
||||
# agent_memory:AgentMemory = parameters.get("_memory")
|
||||
# return await agent_memory.list_experience()
|
||||
# parameters = ParameterDefine.create_parameters({})
|
||||
# list_experience_func = SimpleAIFunction("agent.memory.list_experience",
|
||||
# "list exist experience topics",
|
||||
# list_experience,
|
||||
# parameters)
|
||||
# GlobaToolsLibrary.register_tool_function(list_experience_func)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -198,6 +198,9 @@ class ChatSessionDB:
|
||||
try:
|
||||
conn = self._get_conn()
|
||||
cursor = conn.cursor()
|
||||
if limit == 0:
|
||||
limit = 1024
|
||||
|
||||
cursor.execute("""
|
||||
SELECT MessageID, SessionID, MsgType, PrevMsgID, SenderID, ReceiverID, Timestamp, Topic,Mentions,ContentMIME,Content,ActionName,ActionParams,ActionResult,DoneTime,Status FROM Messages
|
||||
WHERE SessionID = ?
|
||||
@@ -234,6 +237,8 @@ class ChatSessionDB:
|
||||
try:
|
||||
conn = self._get_conn()
|
||||
cursor = conn.cursor()
|
||||
if limit == 0:
|
||||
limit = 1024
|
||||
cursor.execute("""
|
||||
SELECT MessageID, SessionID, MsgType, PrevMsgID, SenderID, ReceiverID, Timestamp, Topic,Mentions,ContentMIME,Content,ActionName,ActionParams,ActionResult,DoneTime,Status FROM Messages
|
||||
WHERE SessionID = ?
|
||||
@@ -296,6 +301,7 @@ class ChatSessionDB:
|
||||
# chat session might be large, so can read / write at stream mode.
|
||||
class AIChatSession:
|
||||
_dbs = {}
|
||||
_sessions = {}
|
||||
#@classmethod
|
||||
#async def get_session_by_id(cls,session_id:str,db_path:str):
|
||||
# db = cls._dbs.get(db_path)
|
||||
@@ -345,18 +351,24 @@ class AIChatSession:
|
||||
cls._dbs[db_path] = db
|
||||
|
||||
result = None
|
||||
for session in cls._sessions.values():
|
||||
if session.owner_id == owner_id and session.topic == session_topic:
|
||||
return session
|
||||
|
||||
session = db.get_chatsession_by_owner_topic(owner_id,session_topic)
|
||||
if session is None:
|
||||
if auto_create:
|
||||
session_id = "CS#" + uuid.uuid4().hex
|
||||
db.insert_chatsession(session_id,owner_id,session_topic,datetime.datetime.now())
|
||||
result = AIChatSession(owner_id,session_id,db)
|
||||
cls._sessions[session_id] = result
|
||||
else:
|
||||
result = AIChatSession(owner_id,session[0],db)
|
||||
result.topic = session_topic
|
||||
result.summarize_pos = session[4]
|
||||
result.summary = session[5]
|
||||
result.openai_thread_id = session[6]
|
||||
cls._sessions[result.session_id] = result
|
||||
|
||||
return result
|
||||
|
||||
@@ -368,6 +380,10 @@ class AIChatSession:
|
||||
cls._dbs[db_path] = db
|
||||
|
||||
result = None
|
||||
session = cls._sessions.get(session_id)
|
||||
if session:
|
||||
return session
|
||||
|
||||
session = db.get_chatsession_by_id(session_id)
|
||||
if session is None:
|
||||
return None
|
||||
@@ -377,6 +393,7 @@ class AIChatSession:
|
||||
result.summarize_pos = session[4]
|
||||
result.summary = session[5]
|
||||
result.openai_thread_id = session[6]
|
||||
cls._sessions[session_id] = result
|
||||
|
||||
return result
|
||||
|
||||
@@ -402,13 +419,13 @@ class AIChatSession:
|
||||
self.topic : str = None
|
||||
self.start_time : str = None
|
||||
self.summarize_pos : int = 0
|
||||
self.summary = None
|
||||
self.summary : str = None
|
||||
self.openai_thread_id = None
|
||||
|
||||
def get_owner_id(self) -> str:
|
||||
return self.owner_id
|
||||
|
||||
def read_history(self, number:int=10,offset=0,order="revers") -> [AgentMsg]:
|
||||
def read_history(self, number:int=0,offset=0,order="revers") -> [AgentMsg]:
|
||||
if order == "revers":
|
||||
msgs = self.db.get_messages(self.session_id, number, offset)
|
||||
else:
|
||||
@@ -444,9 +461,8 @@ class AIChatSession:
|
||||
self.db.insert_message(msg,tags)
|
||||
|
||||
|
||||
def update_think_progress(self,progress:int,new_summary:str) -> None:
|
||||
self.db.update_session_summary(self.session_id,progress,new_summary)
|
||||
self.summarize_pos = progress
|
||||
def update_summary(self,new_summary:str) -> None:
|
||||
self.db.update_session_summary(self.session_id,self.summarize_pos,new_summary)
|
||||
self.summary = new_summary
|
||||
|
||||
def update_openai_thread_id(self,thread_id:str) -> None:
|
||||
|
||||
+85
-113
@@ -39,8 +39,9 @@ class BaseLLMProcess(ABC):
|
||||
#None means system default,
|
||||
# TODO: support abcstract model name like: local-hight,local-low,local-medium,remote-hight,remote-low,remote-medium
|
||||
self.model_name = None
|
||||
self.max_token = 1000 # result_token
|
||||
self.max_prompt_token = 1000 # not include input prompt
|
||||
self.max_token = 2000 # result_token
|
||||
self.max_prompt_token = 2000 # not include input prompt
|
||||
self.chat_summary_token_len = 500
|
||||
self.timeout = 1800 # 30 min
|
||||
|
||||
self.llm_context:LLMProcessContext = None
|
||||
@@ -64,6 +65,9 @@ class BaseLLMProcess(ABC):
|
||||
async def post_llm_process(self,actions:List[ActionNode],input:Dict,llm_result:LLMResult) -> bool:
|
||||
pass
|
||||
|
||||
def get_remain_prompt_length(self,prompt:LLMPrompt,will_append_str:str) -> int:
|
||||
return self.max_prompt_token - ComputeKernel.llm_num_tokens(prompt,self.model_name)
|
||||
|
||||
@abstractmethod
|
||||
async def load_from_config(self,config:dict) -> bool:
|
||||
#self.behavior = config.get("behavior")
|
||||
@@ -166,6 +170,10 @@ class BaseLLMProcess(ABC):
|
||||
|
||||
# Action define in prompt, will be execute after llm compute
|
||||
prompt = await self.prepare_prompt(input)
|
||||
if prompt is None:
|
||||
logger.warn(f"prepare_prompt return None, break llm_process")
|
||||
return LLMResult.from_error_str("prepare_prompt return None")
|
||||
|
||||
max_result_token = self.max_token - ComputeKernel.llm_num_tokens(prompt,self.get_llm_model_name())
|
||||
#if max_result_token < MIN_PREDICT_TOKEN_LEN:
|
||||
# return LLMResult.from_error_str(f"prompt too long,can not predict")
|
||||
@@ -429,14 +437,15 @@ class AgentMessageProcess(LLMAgentBaseProcess):
|
||||
#TODO Is sender an agent?
|
||||
return await self.memory.get_contact_summary(sender_id)
|
||||
|
||||
async def load_chatlogs(self,msg:AgentMsg)->str:
|
||||
async def load_chatlogs(self,msg:AgentMsg,max_length_by_token:int)->str:
|
||||
## like
|
||||
#sender,[2023-11-1 12:00:00]
|
||||
#content
|
||||
return await self.memory.load_chatlogs(msg)
|
||||
return await self.memory.load_chatlogs(msg,max_length_by_token)
|
||||
|
||||
async def get_chat_summary(self,msg:AgentMsg)->str:
|
||||
return await self.memory.get_chat_summary(msg)
|
||||
|
||||
async def get_log_summary(self,msg:AgentMsg)->str:
|
||||
return None
|
||||
|
||||
|
||||
async def get_extend_known_info(self,msg:AgentMsg,prompt:LLMPrompt)->str:
|
||||
@@ -466,18 +475,7 @@ class AgentMessageProcess(LLMAgentBaseProcess):
|
||||
### 信息发送者资料
|
||||
known_info["sender_info"] = await self.sender_info(msg)
|
||||
#prompt.append_system_message(await self.sender_info(self,msg))
|
||||
### 近期的聊天记录
|
||||
chat_record = await self.load_chatlogs(msg)
|
||||
if chat_record:
|
||||
if len(chat_record) > 4:
|
||||
known_info["chat_record"] = chat_record
|
||||
#prompt.append_system_message(await self.load_chatlogs(self,msg))
|
||||
### 交流总结
|
||||
summary = await self.get_log_summary(msg)
|
||||
if summary:
|
||||
if len(summary) > 4:
|
||||
known_info["summary"] = summary
|
||||
#prompt.append_system_message(await self.get_log_summary(self,msg))
|
||||
|
||||
system_prompt_dict["known_info"] = known_info
|
||||
|
||||
prompt.inner_functions =LLMProcessContext.aifunctions_to_inner_functions(self.llm_context.get_all_ai_functions())
|
||||
@@ -490,10 +488,24 @@ class AgentMessageProcess(LLMAgentBaseProcess):
|
||||
logger.info(f"enable kb")
|
||||
|
||||
|
||||
prompt.append_system_message(json.dumps(system_prompt_dict,ensure_ascii=False))
|
||||
## 扩展已知信息 (这可能是一个LLM过程)
|
||||
prompt.append_system_message(await self.get_extend_known_info(msg,prompt))
|
||||
### 根据Token Limit加载聊天记录
|
||||
remain_token = self.get_remain_prompt_length(prompt,json.dumps(system_prompt_dict,ensure_ascii=False))
|
||||
chat_record,is_all = await self.load_chatlogs(msg,remain_token - self.chat_summary_token_len)
|
||||
if chat_record:
|
||||
if len(chat_record) > 4:
|
||||
known_info["chat_record"] = chat_record
|
||||
|
||||
if not is_all :
|
||||
### 如果出触发了Token Limit,则删除几条信息后,加载summary (summary的长度基本是固定的)
|
||||
summary = await self.get_chat_summary(msg)
|
||||
if summary:
|
||||
if len(summary) > 4:
|
||||
known_info["chat_summary"] = summary
|
||||
|
||||
# TODO: extend known info
|
||||
#prompt.append_system_message(await self.get_extend_known_info(msg,prompt))
|
||||
|
||||
prompt.append_system_message(json.dumps(system_prompt_dict,ensure_ascii=False))
|
||||
return prompt
|
||||
|
||||
|
||||
@@ -527,117 +539,77 @@ class AgentMessageProcess(LLMAgentBaseProcess):
|
||||
class AgentSelfThinking(LLMAgentBaseProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
|
||||
async def load_from_config(self, config: dict) -> Coroutine[Any, Any, bool]:
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
async def _load_chat_history(self,token_limit:int):
|
||||
chat_history = {}
|
||||
session_list = AIChatSession.list_session(self.memory.agent_id ,self.memory.memory_db)
|
||||
total_read_msg = 0
|
||||
for session_id in session_list:
|
||||
chatsession = AIChatSession.get_session_by_id(session_id,self.memory.memory_db)
|
||||
session_history = {}
|
||||
session_history["summary"] = chatsession.summary
|
||||
session_history["id"] = chatsession.session_id
|
||||
token_limit -= ComputeKernel.llm_num_tokens_from_text(chatsession.summary,self.model_name)
|
||||
read_history_msg = 0
|
||||
|
||||
if token_limit > 8:
|
||||
# load session chat history
|
||||
cur_pos = chatsession.summarize_pos
|
||||
messages = chatsession.read_history(0,cur_pos,"natural") # read
|
||||
history_str = ""
|
||||
for msg in messages:
|
||||
read_history_msg += 1
|
||||
total_read_msg += 1
|
||||
cur_pos += 1
|
||||
dt = datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
token_limit -= ComputeKernel.llm_num_tokens_from_text(record_str,self.model_name)
|
||||
if token_limit < 8:
|
||||
break
|
||||
|
||||
async def _get_history_prompt_for_think(self,chatsession,summary:str,system_token_len:int,pos:int)->(LLMPrompt,int):
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len
|
||||
history_str = history_str + record_str
|
||||
|
||||
messages = chatsession.read_history(self.history_len,pos,"natural") # read
|
||||
result_token_len = 0
|
||||
result_prompt = LLMPrompt()
|
||||
have_summary = False
|
||||
if summary is not None:
|
||||
if len(summary) > 1:
|
||||
have_summary = True
|
||||
if read_history_msg >= 2:
|
||||
session_history["history"] = history_str
|
||||
chat_history[session_id] = session_history
|
||||
chatsession.summarize_pos = cur_pos
|
||||
|
||||
if have_summary:
|
||||
result_prompt.messages.append({"role":"user","content":summary})
|
||||
result_token_len -= len(summary)
|
||||
else:
|
||||
result_prompt.messages.append({"role":"user","content":"There is no summary yet."})
|
||||
result_token_len -= 6
|
||||
|
||||
read_history_msg = 0
|
||||
history_str : str = ""
|
||||
for msg in messages:
|
||||
read_history_msg += 1
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
history_str = history_str + record_str
|
||||
|
||||
history_len -= len(msg.body)
|
||||
result_token_len += len(msg.body)
|
||||
if history_len < 0:
|
||||
logger.warning(f"_get_prompt_from_session reach limit of token,just read {read_history_msg} history message.")
|
||||
break
|
||||
|
||||
result_prompt.messages.append({"role":"user","content":history_str})
|
||||
return result_prompt,pos+read_history_msg
|
||||
|
||||
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}")
|
||||
chatsession = AIChatSession.get_session_by_id(session_id,self.chat_db)
|
||||
|
||||
while True:
|
||||
cur_pos = chatsession.summarize_pos
|
||||
summary = chatsession.summary
|
||||
prompt:LLMPrompt = LLMPrompt()
|
||||
#prompt.append(self._get_agent_prompt())
|
||||
prompt.append(await self._get_agent_think_prompt())
|
||||
system_prompt_len = ComputeKernel.llm_num_tokens(prompt)
|
||||
#think env?
|
||||
history_prompt,next_pos = await self._get_history_prompt_for_think(chatsession,summary,system_prompt_len,cur_pos)
|
||||
prompt.append(history_prompt)
|
||||
is_finish = next_pos - cur_pos < 2
|
||||
if is_finish:
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} is finished!,no more history")
|
||||
break
|
||||
#3) llm summarize chat history
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt)
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"think_chatsession llm compute error:{task_result.error_str}")
|
||||
break
|
||||
else:
|
||||
new_summary= task_result.result_str
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} from {cur_pos} to {next_pos} summary:{new_summary}")
|
||||
chatsession.update_think_progress(next_pos,new_summary)
|
||||
return
|
||||
logger.info(f"load_chat_history reach token limit,load {total_read_msg} history messages.")
|
||||
return chat_history
|
||||
|
||||
if total_read_msg < 2:
|
||||
logger.info(f"load_chat_history: no history messages,return NONE")
|
||||
return None
|
||||
|
||||
return chat_history
|
||||
|
||||
|
||||
async def prepare_prompt(self,input:Dict) -> LLMPrompt:
|
||||
prompt = LLMPrompt()
|
||||
|
||||
record_list = input.get("record_list")
|
||||
context_info = input.get("context_info")
|
||||
|
||||
if record_list is None:
|
||||
logger.error(f"AgentSelfThinking prepare_prompt failed! input not found")
|
||||
return None
|
||||
|
||||
prompt.append_user_message(json.dumps(record_list,ensure_ascii=False))
|
||||
|
||||
system_prompt_dict = self.prepare_role_system_prompt(context_info)
|
||||
|
||||
# Known_info is the SESSION summary of the existence, the current task work record summary,
|
||||
known_info = {}
|
||||
have_known_info = False
|
||||
known_session_list = input.get("known_session_list")
|
||||
known_task_list = input.get("known_task_list")
|
||||
known_contact_list = input.get("known_contact_list")
|
||||
known_experience_list = input.get("known_experience_list")
|
||||
if known_session_list:
|
||||
known_info["known_session_list"] = known_session_list
|
||||
have_known_info = True
|
||||
if known_task_list:
|
||||
known_info["known_task_list"] = known_task_list
|
||||
have_known_info = True
|
||||
if known_contact_list:
|
||||
known_info["known_contact_list"] = known_contact_list
|
||||
have_known_info = True
|
||||
if known_experience_list:
|
||||
known_info["known_experience_list"] = known_experience_list
|
||||
have_known_info = True
|
||||
|
||||
if have_known_info:
|
||||
system_prompt_dict["known_info"] = known_info
|
||||
|
||||
token_remain = self.get_remain_prompt_length(prompt,json.dumps(system_prompt_dict,ensure_ascii=False))
|
||||
chat_history = await self._load_chat_history(token_remain)
|
||||
if chat_history is None:
|
||||
logger.info(f"prepare_prompt: no history messages,return NONE")
|
||||
return None
|
||||
|
||||
prompt.inner_functions =LLMProcessContext.aifunctions_to_inner_functions(self.llm_context.get_all_ai_functions())
|
||||
|
||||
prompt.append_system_message(json.dumps(system_prompt_dict,ensure_ascii=False))
|
||||
prompt.append_user_message(json.dumps(chat_history,ensure_ascii=False))
|
||||
return prompt
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionNode],input:Dict,llm_result:LLMResult) -> bool:
|
||||
action_params = {}
|
||||
|
||||
@@ -8,7 +8,7 @@ class ParameterDefine:
|
||||
self.type:str = "string"
|
||||
self.enum:List[str] = None
|
||||
self.description = desc
|
||||
self.is_required = False
|
||||
self.is_required = True
|
||||
|
||||
@classmethod
|
||||
def create_parameters(cls,json_obj:dict) -> Dict[str,'ParameterDefine']:
|
||||
|
||||
@@ -152,7 +152,9 @@ class AIOS_Shell:
|
||||
#AgentManager.get_instance().register_environment("fs", FilesystemEnvironment)
|
||||
#AgentManager.get_instance().register_environment("knowledge", LocalKnowledgeBase)
|
||||
AgentWorkspace.register_ai_functions()
|
||||
AgentMemory.register_ai_functions()
|
||||
ShellEnvironment.register_ai_functions()
|
||||
|
||||
|
||||
if await AgentManager.get_instance().initial() is not True:
|
||||
logger.error("agent manager initial failed!")
|
||||
@@ -256,7 +258,7 @@ class AIOS_Shell:
|
||||
|
||||
|
||||
def get_version(self) -> str:
|
||||
return "0.5.1"
|
||||
return "0.5.2"
|
||||
|
||||
async def send_msg(self,msg:str,target_id:str,topic:str,sender:str = None, msg_mime:str=None) -> str:
|
||||
if sender == self.username:
|
||||
|
||||
Reference in New Issue
Block a user