rollback agent memory to "chat session history & session summary"

This commit is contained in:
Liu Zhicong
2024-03-20 18:47:58 -07:00
parent 3601cd9bd3
commit 342464e386
8 changed files with 273 additions and 288 deletions
+10 -10
View File
@@ -14,7 +14,6 @@ Only clearly specifying the task you completed can be completed independently.
[behavior.on_message]
type="AgentMessageProcess"
# TODO: 是否应该自动记录 inner function和action的执行细节
mutil_model="gpt-4-vision-preview"
asr_model="openai-whisper"
tts_model="tts-1"
@@ -167,7 +166,8 @@ process_description="""
reply_format = """
The Response must be directly parsed by `python json.loads`. Here is an example:
{
resp:'$think step by step, how to check the todo',
resp: '$simport report about what you do',
actions: [{
name: '$action1_name',
$param_name: '$parm' #Optional, fill in only if the action has parameters.
}, ...
@@ -179,24 +179,24 @@ llm_context.actions.enable = ["agent.workspace.update_todo"]
llm_context.functions.enable = ["agent.workspace.read_file","agent.workspace.list_dir","system.shell.exec","system.shell.run_code","aigc.image_2_text","aigc.voice_2_text","web.search.duckduckgo"]
[behavior.self_thinking2]
[behavior.self_thinking]
# self thing的主要目的是对各种chatlog,worklog进行分析,并更新面向人和事的summary。
# TODO,先不支持worklog,先支持好chatlog
type="AgentSelfThinking"
process_description="""
You are very good at thinking and summarizing what you have already happened。Your input is a chat history and work record,After you think about it, you will follow the requirements below to generate abstract.
You are very good at thinking and summarizing what you have already happened。Your input is chat history and work records,After you think about it, you will follow the requirements below to generate abstract.
1. Try to understand the theme of each sentence, and call the relevant operation to record the relationship between the dialogue and the theme
2. Try to analyze the personality of different people involved in information
3. Try to summarize important events in the information and record it
4. Try to understand the attitude of different people on different topics or events
5. Pay attention to the time order when summarizing, and combine the summary you have done to update Summary
6. The summary of the generation cannot exceed 400 token
7. 思考的目的是让自己未来的工作更加高效
8. 总结中只包含有长期价值和未完成的事情,已经完成的事情不需要总结
6. The summary of the generation cannot exceed 500 token
"""
reply_format = """
The Response must be directly parsed by `python json.loads`. Here is an example:
{
resp:'$Summary in one sentence',
resp: '$simport report about what you do',
actions: [{
name: '$action1_name',
$param_name: '$parm' #Optional, fill in only if the action has parameters.
}, ...
@@ -204,8 +204,8 @@ The Response must be directly parsed by `python json.loads`. Here is an example:
}
"""
context="Your Principal is {owner}, now in {location}, time: {now}, weather: {weather}."
llm_context.actions.enable = ["agent.memory.update_summary","agent.memory.update_contact_summary","agent.memory.update_relation_summary","agent.memory.set_experience"]
llm_context.functions.enable = ["agent.memory.get_summary","agent.memory.get_contact_summary","agent.memory.list_summary","agent.memory.get_relation_summary","agent.memory.get_experience"]
llm_context.actions.enable = ["agent.memory.update_chat_summary"]
#[behavior.self_improve]
+1 -1
View File
@@ -13,7 +13,7 @@ class EmbeddingEnvironment(SimpleEnvironment):
query_param = {
"tokens": "key words to query",
"types": "prefered knowledge types, one or more of [text, image]",
"index": "index of query result"
"limit": "index of query result"
}
self.add_ai_function(SimpleAIFunction("query_knowledge",
"vector query content from local knowledge base",
+4 -7
View File
@@ -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
+146 -148
View File
@@ -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")
return histroy_str,is_all
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
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:
#
@@ -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)
+21 -5
View File
@@ -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:
+82 -110
View File
@@ -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
@@ -528,116 +540,76 @@ 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
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
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
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
history_str = history_str + record_str
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
if read_history_msg >= 2:
session_history["history"] = history_str
chat_history[session_id] = session_history
chatsession.summarize_pos = cur_pos
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 = {}
+1 -1
View File
@@ -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']:
+3 -1
View File
@@ -152,8 +152,10 @@ 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!")
return False
@@ -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: