rollback agent memory to "chat session history & session summary"
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
+78
-106
@@ -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 _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
|
||||
|
||||
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 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
|
||||
|
||||
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
|
||||
history_str : str = ""
|
||||
|
||||
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
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
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
|
||||
|
||||
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
|
||||
if read_history_msg >= 2:
|
||||
session_history["history"] = history_str
|
||||
chat_history[session_id] = session_history
|
||||
chatsession.summarize_pos = cur_pos
|
||||
|
||||
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,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:
|
||||
|
||||
Reference in New Issue
Block a user