1) Do some rename refactor ,prepare for LLMProcess refactor
2) Fix merge bugs.
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
|
||||
from .proto.agent_msg import *
|
||||
from .proto.compute_task import *
|
||||
from .proto.ai_function import *
|
||||
from .proto.agent_task import *
|
||||
|
||||
from .agent.agent_base import AgentPrompt,CustomAIAgent, AgentTodo
|
||||
from .agent.agent_base import *
|
||||
from .agent.chatsession import AIChatSession
|
||||
from .agent.agent import AIAgent,AIAgentTemplete, BaseAIAgent
|
||||
from .agent.role import AIRole,AIRoleGroup
|
||||
# from .agent.workflow import Workflow
|
||||
from .agent.ai_function import SimpleAIFunction, SimpleAIOperation
|
||||
from .agent.workflow import Workflow
|
||||
|
||||
from .frame.compute_kernel import ComputeKernel,ComputeTask,ComputeTaskResult,ComputeTaskState,ComputeTaskType
|
||||
from .frame.compute_node import ComputeNode,LocalComputeNode
|
||||
@@ -20,7 +21,7 @@ from .environment.environment import BaseEnvironment,SimpleEnvironment,Composite
|
||||
# from .environment.workflow_env import WorkflowEnvironment,CalenderEnvironment,CalenderEvent,PaintEnvironment
|
||||
from .environment.text_to_speech_function import TextToSpeechFunction
|
||||
from .environment.image_2_text_function import Image2TextFunction
|
||||
from .environment.workspace_env import WorkspaceEnvironment,TodoListEnvironment,TodoListType
|
||||
from .environment.workspace_env import WorkspaceEnvironment
|
||||
|
||||
from .storage.storage import ResourceLocation,AIStorage,UserConfig,UserConfigItem
|
||||
|
||||
|
||||
+47
-45
@@ -13,10 +13,12 @@ import copy
|
||||
import sys
|
||||
|
||||
from ..proto.agent_msg import AgentMsg
|
||||
from ..proto.ai_function import *
|
||||
from ..proto.agent_task import *
|
||||
from ..proto.compute_task import *
|
||||
|
||||
from .agent_base import *
|
||||
from .chatsession import *
|
||||
from .ai_function import *
|
||||
from ..environment.workspace_env import WorkspaceEnvironment, TodoListType
|
||||
|
||||
from ..frame.contact_manager import ContactManager,Contact,FamilyMember
|
||||
@@ -69,7 +71,7 @@ class AIAgentTemplete:
|
||||
self.template_id:str = None
|
||||
self.introduce:str = None
|
||||
self.author:str = None
|
||||
self.prompt:AgentPrompt = None
|
||||
self.prompt:LLMPrompt = None
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
if config.get("llm_model_name") is not None:
|
||||
@@ -79,7 +81,7 @@ class AIAgentTemplete:
|
||||
if config.get("template_id") is not None:
|
||||
self.template_id = config["template_id"]
|
||||
if config.get("prompt") is not None:
|
||||
self.prompt = AgentPrompt()
|
||||
self.prompt = LLMPrompt()
|
||||
if self.prompt.load_from_config(config["prompt"]) is False:
|
||||
logger.error("load prompt from config failed!")
|
||||
return False
|
||||
@@ -90,9 +92,9 @@ class AIAgentTemplete:
|
||||
|
||||
class AIAgent(BaseAIAgent):
|
||||
def __init__(self) -> None:
|
||||
self.role_prompt:AgentPrompt = None
|
||||
self.agent_prompt:AgentPrompt = None
|
||||
self.agent_think_prompt:AgentPrompt = None
|
||||
self.role_prompt:LLMPrompt = None
|
||||
self.agent_prompt:LLMPrompt = None
|
||||
self.agent_think_prompt:LLMPrompt = None
|
||||
self.llm_model_name:str = None
|
||||
self.max_token_size:int = 128000
|
||||
self.agent_energy = 15
|
||||
@@ -149,26 +151,26 @@ class AIAgent(BaseAIAgent):
|
||||
self.enable_thread = bool(config["enable_thread"])
|
||||
|
||||
if config.get("prompt") is not None:
|
||||
self.agent_prompt = AgentPrompt()
|
||||
self.agent_prompt = LLMPrompt()
|
||||
self.agent_prompt.load_from_config(config["prompt"])
|
||||
|
||||
if config.get("think_prompt") is not None:
|
||||
self.agent_think_prompt = AgentPrompt()
|
||||
self.agent_think_prompt = LLMPrompt()
|
||||
self.agent_think_prompt.load_from_config(config["think_prompt"])
|
||||
|
||||
def load_todo_config(todo_type:str) -> bool:
|
||||
todo_config = config.get(todo_type)
|
||||
if todo_config is not None:
|
||||
if todo_config.get("do") is not None:
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["do"])
|
||||
self.todo_prompts[todo_type]["do"] = prompt
|
||||
if todo_config.get("check") is not None:
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["check"])
|
||||
self.todo_prompts[todo_type]["check"] = prompt
|
||||
if todo_config.get("review_prompt") is not None:
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["review_prompt"])
|
||||
self.todo_prompts[todo_type]["review"] = prompt
|
||||
|
||||
@@ -224,16 +226,16 @@ class AIAgent(BaseAIAgent):
|
||||
def get_max_token_size(self) -> int:
|
||||
return self.max_token_size
|
||||
|
||||
def get_agent_role_prompt(self) -> AgentPrompt:
|
||||
def get_agent_role_prompt(self) -> LLMPrompt:
|
||||
return self.role_prompt
|
||||
|
||||
def _get_remote_user_prompt(self,remote_user:str) -> AgentPrompt:
|
||||
def _get_remote_user_prompt(self,remote_user:str) -> LLMPrompt:
|
||||
cm = ContactManager.get_instance()
|
||||
contact = cm.find_contact_by_name(remote_user)
|
||||
if contact is None:
|
||||
#create guest prompt
|
||||
if self.guest_prompt_str is not None:
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":self.guest_prompt_str}
|
||||
return prompt
|
||||
return None
|
||||
@@ -241,25 +243,25 @@ class AIAgent(BaseAIAgent):
|
||||
if contact.is_family_member:
|
||||
if self.owner_promp_str is not None:
|
||||
real_str = self.owner_promp_str.format_map(contact.to_dict())
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":real_str}
|
||||
return prompt
|
||||
else:
|
||||
if self.contact_prompt_str is not None:
|
||||
real_str = self.contact_prompt_str.format_map(contact.to_dict())
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":real_str}
|
||||
return prompt
|
||||
|
||||
return None
|
||||
|
||||
def get_agent_prompt(self) -> AgentPrompt:
|
||||
def get_agent_prompt(self) -> LLMPrompt:
|
||||
return self.agent_prompt
|
||||
|
||||
async def _get_agent_think_prompt(self) -> AgentPrompt:
|
||||
async def _get_agent_think_prompt(self) -> LLMPrompt:
|
||||
return self.agent_think_prompt
|
||||
|
||||
def _format_msg_by_env_value(self,prompt:AgentPrompt):
|
||||
def _format_msg_by_env_value(self,prompt:LLMPrompt):
|
||||
for msg in prompt.messages:
|
||||
old_content = msg.get("content")
|
||||
msg["content"] = old_content.format_map(self.agent_workspace)
|
||||
@@ -284,7 +286,7 @@ class AIAgent(BaseAIAgent):
|
||||
return image_path
|
||||
|
||||
async def _process_msg(self,msg:AgentMsg,workspace = None) -> AgentMsg:
|
||||
msg_prompt = AgentPrompt()
|
||||
msg_prompt = LLMPrompt()
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
need_process = False
|
||||
if msg.is_image_msg():
|
||||
@@ -378,7 +380,7 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
workspace = self.get_workspace_by_msg(msg)
|
||||
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
if workspace:
|
||||
prompt.append(workspace.get_prompt())
|
||||
prompt.append(workspace.get_role_prompt(self.agent_id))
|
||||
@@ -390,7 +392,7 @@ class AIAgent(BaseAIAgent):
|
||||
if self.need_session_summmary(msg,chatsession):
|
||||
# get relate session(todos) summary
|
||||
summary = self.llm_select_session_summary(msg,chatsession)
|
||||
prompt.append(AgentPrompt(summary))
|
||||
prompt.append(LLMPrompt(summary))
|
||||
|
||||
known_info_str = "# Known information\n"
|
||||
have_known_info = False
|
||||
@@ -399,7 +401,7 @@ class AIAgent(BaseAIAgent):
|
||||
have_known_info = True
|
||||
known_info_str += f"## todo\n{todos_str}\n"
|
||||
inner_functions,function_token_len = BaseAIAgent.get_inner_functions(self.agent_workspace)
|
||||
system_prompt_len = self.token_len(prompt=prompt)
|
||||
system_prompt_len = ComputeKernel.llm_num_tokens(prompt)
|
||||
input_len = len(msg.body)
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
history_str,history_token_len = await self._get_prompt_from_session_for_groupchat(chatsession,system_prompt_len + function_token_len,input_len)
|
||||
@@ -410,7 +412,7 @@ class AIAgent(BaseAIAgent):
|
||||
known_info_str += history_str
|
||||
|
||||
if have_known_info:
|
||||
known_info_prompt = AgentPrompt(known_info_str)
|
||||
known_info_prompt = LLMPrompt(known_info_str)
|
||||
prompt.append(known_info_prompt) # chat context
|
||||
|
||||
prompt.append(msg_prompt)
|
||||
@@ -436,7 +438,7 @@ class AIAgent(BaseAIAgent):
|
||||
final_result = llm_result.resp
|
||||
|
||||
|
||||
await workspace.exec_op_list(llm_result.op_list,self.agent_id)
|
||||
await workspace.exec_op_list(llm_result.action_list,self.agent_id)
|
||||
|
||||
is_ignore = False
|
||||
result_prompt_str = ""
|
||||
@@ -471,12 +473,12 @@ class AIAgent(BaseAIAgent):
|
||||
return None
|
||||
|
||||
|
||||
async def _get_history_prompt_for_think(self,chatsession:AIChatSession,summary:str,system_token_len:int,pos:int)->(AgentPrompt,int):
|
||||
async def _get_history_prompt_for_think(self,chatsession:AIChatSession,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 = AgentPrompt()
|
||||
result_prompt = LLMPrompt()
|
||||
have_summary = False
|
||||
if summary is not None:
|
||||
if len(summary) > 1:
|
||||
@@ -511,7 +513,7 @@ class AIAgent(BaseAIAgent):
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len - input_token_len
|
||||
messages = chatsession.read_history(self.history_len) # read
|
||||
result_token_len = 0
|
||||
result_prompt = AgentPrompt()
|
||||
result_prompt = LLMPrompt()
|
||||
read_history_msg = 0
|
||||
for msg in reversed(messages):
|
||||
read_history_msg += 1
|
||||
@@ -569,13 +571,13 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
async def _llm_read_report(self,report:AgentReport,worksapce:WorkspaceEnvironment):
|
||||
work_summary = worksapce.get_work_summary(self.agent_id)
|
||||
prompt : AgentPrompt = AgentPrompt()
|
||||
prompt : LLMPrompt = LLMPrompt()
|
||||
prompt.append(self.agent_prompt)
|
||||
prompt.append(worksapce.get_role_prompt(self.agent_id))
|
||||
prompt.append(self.read_report_prompt)
|
||||
# report is a message from other agent(human) about work
|
||||
prompt.append(AgentPrompt(work_summary))
|
||||
prompt.append(AgentPrompt(report.content))
|
||||
prompt.append(LLMPrompt(work_summary))
|
||||
prompt.append(LLMPrompt(report.content))
|
||||
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt)
|
||||
|
||||
@@ -606,7 +608,7 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
do_prompts = self._can_do_todo(todo_list_type, todo)
|
||||
if do_prompts:
|
||||
prompt : AgentPrompt = AgentPrompt()
|
||||
prompt : LLMPrompt = LLMPrompt()
|
||||
prompt.append(self.agent_prompt)
|
||||
prompt.append(workspace.get_role_prompt(self.agent_id))
|
||||
prompt.append(do_prompts)
|
||||
@@ -635,13 +637,13 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
check_prompts = self._can_check_todo(todo_list_type, todo)
|
||||
if check_prompts:
|
||||
prompt : AgentPrompt = AgentPrompt()
|
||||
prompt : LLMPrompt = LLMPrompt()
|
||||
prompt.append(self.agent_prompt)
|
||||
prompt.append(workspace.get_role_prompt(self.agent_id))
|
||||
prompt.append(check_prompts)
|
||||
|
||||
if todo.last_check_result:
|
||||
prompt.append(AgentPrompt(todo.last_check_result))
|
||||
prompt.append(LLMPrompt(todo.last_check_result))
|
||||
|
||||
prompt.append(todo.detail)
|
||||
prompt.append(todo.result)
|
||||
@@ -669,7 +671,7 @@ class AIAgent(BaseAIAgent):
|
||||
prompt.append(review_prompts)
|
||||
|
||||
todo_tree = todo_list.get_todo_tree("/")
|
||||
prompt.append(AgentPrompt(todo_tree))
|
||||
prompt.append(LLMPrompt(todo_tree))
|
||||
|
||||
do_result : AgentTodoResult = await self._llm_review_todo(todo, prompt, workspace)
|
||||
todo.last_review_time = datetime.datetime.now().timestamp()
|
||||
@@ -690,7 +692,7 @@ class AIAgent(BaseAIAgent):
|
||||
logger.info(f"agent {self.agent_id} ,check:{check_count} todo,do:{do_count} todo.")
|
||||
|
||||
|
||||
def _can_review_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> AgentPrompt:
|
||||
def _can_review_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> LLMPrompt:
|
||||
do_prompts = self.todo_prompts[todo_list_type].get("review")
|
||||
if not do_prompts:
|
||||
return None
|
||||
@@ -701,7 +703,7 @@ class AIAgent(BaseAIAgent):
|
||||
return do_prompts
|
||||
|
||||
|
||||
def _can_check_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> AgentPrompt:
|
||||
def _can_check_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> LLMPrompt:
|
||||
do_prompts = self.todo_prompts[todo_list_type].get("check")
|
||||
if not do_prompts:
|
||||
return None
|
||||
@@ -720,7 +722,7 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
return do_prompts
|
||||
|
||||
def _can_do_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> AgentPrompt:
|
||||
def _can_do_todo(self, todo_list_type: TodoListType, todo:AgentTodo) -> LLMPrompt:
|
||||
do_prompts = self.todo_prompts[todo_list_type].get("do")
|
||||
if not do_prompts:
|
||||
return None
|
||||
@@ -739,7 +741,7 @@ class AIAgent(BaseAIAgent):
|
||||
|
||||
return do_prompts
|
||||
|
||||
async def _llm_do_todo(self, todo: AgentTodo, prompt: AgentPrompt, workspace: WorkspaceEnvironment) -> AgentTodoResult:
|
||||
async def _llm_do_todo(self, todo: AgentTodo, prompt: LLMPrompt, workspace: WorkspaceEnvironment) -> AgentTodoResult:
|
||||
result = AgentTodoResult()
|
||||
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt, is_json_resp=True)
|
||||
@@ -763,7 +765,7 @@ class AIAgent(BaseAIAgent):
|
||||
resp = await AIBus.get_default_bus().post_message(msg)
|
||||
logging.info(f"agent {self.agent_id} send msg to {msg.target} result:{resp}")
|
||||
|
||||
result_str, have_error = await workspace.exec_op_list(llm_result.op_list, self.agent_id)
|
||||
result_str, have_error = await workspace.exec_op_list(llm_result.action_list, self.agent_id)
|
||||
if have_error:
|
||||
result.result_code = AgentTodoResult.TODO_RESULT_CODE_EXEC_OP_ERROR
|
||||
#result.error_str = error_str
|
||||
@@ -771,7 +773,7 @@ class AIAgent(BaseAIAgent):
|
||||
result.result_str = result_str
|
||||
return result
|
||||
|
||||
async def _llm_check_todo(self, todo: AgentTodo, prompt: AgentPrompt, workspace: WorkspaceEnvironment) -> AgentTodoResult:
|
||||
async def _llm_check_todo(self, todo: AgentTodo, prompt: LLMPrompt, workspace: WorkspaceEnvironment) -> AgentTodoResult:
|
||||
result = AgentTodoResult()
|
||||
|
||||
inner_functions,_ = BaseAIAgent.get_inner_functions(workspace)
|
||||
@@ -786,7 +788,7 @@ class AIAgent(BaseAIAgent):
|
||||
todo.last_check_result = task_result.result_str
|
||||
return result
|
||||
|
||||
async def _llm_review_todo(self, todo:AgentTodo, prompt: AgentPrompt, workspace: WorkspaceEnvironment):
|
||||
async def _llm_review_todo(self, todo:AgentTodo, prompt: LLMPrompt, workspace: WorkspaceEnvironment):
|
||||
inner_functions,_ = BaseAIAgent.get_inner_functions(workspace)
|
||||
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt,inner_functions=inner_functions)
|
||||
@@ -842,10 +844,10 @@ class AIAgent(BaseAIAgent):
|
||||
while True:
|
||||
cur_pos = chatsession.summarize_pos
|
||||
summary = chatsession.summary
|
||||
prompt:AgentPrompt = AgentPrompt()
|
||||
prompt:LLMPrompt = LLMPrompt()
|
||||
#prompt.append(self._get_agent_prompt())
|
||||
prompt.append(await self._get_agent_think_prompt())
|
||||
system_prompt_len = self.token_len(prompt=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)
|
||||
@@ -864,7 +866,7 @@ class AIAgent(BaseAIAgent):
|
||||
chatsession.update_think_progress(next_pos,new_summary)
|
||||
return
|
||||
|
||||
async def get_prompt_from_session(self,chatsession:AIChatSession,system_token_len,input_token_len) -> AgentPrompt:
|
||||
async def get_prompt_from_session(self,chatsession:AIChatSession,system_token_len,input_token_len) -> LLMPrompt:
|
||||
# TODO: get prompt from group chat is different from single chat
|
||||
if self.enable_thread:
|
||||
return None
|
||||
|
||||
+10
-405
@@ -11,400 +11,15 @@ import shlex
|
||||
import json
|
||||
from typing import List, Tuple
|
||||
|
||||
from .ai_function import FunctionItem, AIFunction
|
||||
from ..proto.agent_msg import AgentMsg, AgentMsgType
|
||||
from ..proto.compute_task import ComputeTaskResult,ComputeTaskResultCode
|
||||
from ..environment.environment import BaseEnvironment
|
||||
from ..proto.ai_function import *
|
||||
from ..proto.agent_msg import *
|
||||
from ..proto.compute_task import *
|
||||
from ..environment.environment import *
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgentPrompt:
|
||||
def __init__(self,prompt_str = None) -> None:
|
||||
self.messages = []
|
||||
if prompt_str:
|
||||
self.messages.append({"role":"user","content":prompt_str})
|
||||
self.system_message = None
|
||||
|
||||
def as_str(self)->str:
|
||||
result_str = ""
|
||||
if self.system_message:
|
||||
result_str += self.system_message.get("role") + ":" + self.system_message.get("content") + "\n"
|
||||
if self.messages:
|
||||
for msg in self.messages:
|
||||
result_str += msg.get("role") + ":" + msg.get("content") + "\n"
|
||||
|
||||
return result_str
|
||||
|
||||
def to_message_list(self):
|
||||
result = []
|
||||
if self.system_message:
|
||||
result.append(self.system_message)
|
||||
result.extend(self.messages)
|
||||
return result
|
||||
|
||||
def append(self,prompt):
|
||||
if prompt is None:
|
||||
return
|
||||
|
||||
if prompt.system_message is not None:
|
||||
if self.system_message is None:
|
||||
self.system_message = copy.deepcopy(prompt.system_message)
|
||||
else:
|
||||
self.system_message["content"] += prompt.system_message.get("content")
|
||||
|
||||
self.messages.extend(prompt.messages)
|
||||
|
||||
def load_from_config(self,config:list) -> bool:
|
||||
if isinstance(config,list) is not True:
|
||||
logger.error("prompt is not list!")
|
||||
return False
|
||||
self.messages = []
|
||||
for msg in config:
|
||||
if msg.get("content"):
|
||||
if msg.get("role") == "system":
|
||||
self.system_message = msg
|
||||
else:
|
||||
self.messages.append(msg)
|
||||
else:
|
||||
logger.error("prompt message has no content!")
|
||||
return True
|
||||
|
||||
class LLMResult:
|
||||
def __init__(self) -> None:
|
||||
self.state : str = "ignore"
|
||||
self.resp : str = ""
|
||||
self.raw_resp = None
|
||||
self.paragraphs : dict[str,FunctionItem] = []
|
||||
|
||||
|
||||
self.post_msgs : List[AgentMsg] = []
|
||||
self.send_msgs : List[AgentMsg] = []
|
||||
self.calls : List[FunctionItem] = []
|
||||
self.post_calls : List[FunctionItem] = []
|
||||
self.op_list : List[FunctionItem] = [] # op_list is a optimize design for saving token
|
||||
@classmethod
|
||||
def from_json_str(self,llm_json_str:str) -> 'LLMResult':
|
||||
r = LLMResult()
|
||||
if llm_json_str is None:
|
||||
r.state = "ignore"
|
||||
return r
|
||||
if llm_json_str == "ignore":
|
||||
r.state = "ignore"
|
||||
return r
|
||||
|
||||
llm_json = json.loads(llm_json_str)
|
||||
r.state = llm_json.get("state")
|
||||
r.resp = llm_json.get("resp")
|
||||
r.raw_resp = llm_json
|
||||
|
||||
post_msgs = llm_json.get("post_msg")
|
||||
r.post_msgs = []
|
||||
if post_msgs:
|
||||
for msg in post_msgs:
|
||||
new_msg = AgentMsg()
|
||||
target_id = msg.get("target")
|
||||
msg_content = msg.get("content")
|
||||
new_msg.set("",target_id,msg_content)
|
||||
r.post_msgs.append(new_msg)
|
||||
#new_msg.msg_type = AgentMsgType.TYPE_MSG
|
||||
|
||||
r.calls = llm_json.get("calls")
|
||||
r.post_calls = llm_json.get("post_calls")
|
||||
r.op_list = llm_json.get("op_list")
|
||||
|
||||
return r
|
||||
|
||||
@classmethod
|
||||
def from_str(self,llm_result_str:str,valid_func:List[str]=None) -> 'LLMResult':
|
||||
r = LLMResult()
|
||||
|
||||
if llm_result_str is None:
|
||||
r.state = "ignore"
|
||||
return r
|
||||
if llm_result_str == "ignore":
|
||||
r.state = "ignore"
|
||||
return r
|
||||
|
||||
if llm_result_str[0] == "{":
|
||||
return LLMResult.from_json_str(llm_result_str)
|
||||
# if llm_result_str.startswith("json"):
|
||||
# return LLMResult.from_json_str(llm_result_str[4:])
|
||||
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
|
||||
def check_args(func_item:FunctionItem):
|
||||
match func_name:
|
||||
case "send_msg":# /send_msg $target_id
|
||||
if len(func_args) != 1:
|
||||
return False
|
||||
|
||||
new_msg = AgentMsg()
|
||||
target_id = func_item.args[0]
|
||||
msg_content = func_item.body
|
||||
new_msg.set("",target_id,msg_content)
|
||||
|
||||
r.send_msgs.append(new_msg)
|
||||
is_need_wait = True
|
||||
return True
|
||||
|
||||
case "post_msg":# /post_msg $target_id
|
||||
if len(func_args) != 1:
|
||||
return False
|
||||
|
||||
new_msg = AgentMsg()
|
||||
target_id = func_item.args[0]
|
||||
msg_content = func_item.body
|
||||
new_msg.set("",target_id,msg_content)
|
||||
r.post_msgs.append(new_msg)
|
||||
return True
|
||||
|
||||
case "call":# /call $func_name $args_str
|
||||
r.calls.append(func_item)
|
||||
is_need_wait = True
|
||||
return True
|
||||
case "post_call": # /post_call $func_name,$args_str
|
||||
r.post_calls.append(func_item)
|
||||
return True
|
||||
case _:
|
||||
if valid_func is not None:
|
||||
if func_name in valid_func:
|
||||
r.paragraphs[func_name] = func_item
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
current_func : FunctionItem = None
|
||||
for line in lines:
|
||||
if line.startswith("##/"):
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
|
||||
func_name,func_args = AgentMsg.parse_function_call(line[3:])
|
||||
current_func = FunctionItem(func_name,func_args)
|
||||
else:
|
||||
if current_func:
|
||||
current_func.append_body(line + "\n")
|
||||
else:
|
||||
r.resp += line + "\n"
|
||||
|
||||
if current_func:
|
||||
if check_args(current_func) is False:
|
||||
r.resp += current_func.dumps()
|
||||
|
||||
if len(r.send_msgs) > 0 or len(r.calls) > 0:
|
||||
r.state = "waiting"
|
||||
else:
|
||||
r.state = "reponsed"
|
||||
|
||||
return r
|
||||
|
||||
class AgentReport:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class AgentTodoResult:
|
||||
TODO_RESULT_CODE_OK = 0,
|
||||
TODO_RESULT_CODE_LLM_ERROR = 1,
|
||||
TODO_RESULT_CODE_EXEC_OP_ERROR = 2
|
||||
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.result_code = AgentTodoResult.TODO_RESULT_CODE_OK
|
||||
self.result_str = None
|
||||
self.error_str = None
|
||||
self.op_list = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
result = {}
|
||||
result["result_code"] = self.result_code
|
||||
result["result_str"] = self.result_str
|
||||
result["error_str"] = self.error_str
|
||||
result["op_list"] = self.op_list
|
||||
return result
|
||||
|
||||
|
||||
class AgentTodo:
|
||||
TODO_STATE_WAIT_ASSIGN = "wait_assign"
|
||||
TODO_STATE_INIT = "init"
|
||||
|
||||
TODO_STATE_PENDING = "pending"
|
||||
TODO_STATE_WAITING_CHECK = "wait_check"
|
||||
TODO_STATE_EXEC_FAILED = "exec_failed"
|
||||
TDDO_STATE_CHECKFAILED = "check_failed"
|
||||
|
||||
TODO_STATE_CANCEL = "cancel"
|
||||
TODO_STATE_DONE = "done"
|
||||
TODO_STATE_REVIEWED = "reviewed"
|
||||
TODO_STATE_EXPIRED = "expired"
|
||||
|
||||
def __init__(self):
|
||||
self.todo_id = "todo#" + uuid.uuid4().hex
|
||||
self.title = None
|
||||
self.detail = None
|
||||
self.todo_path = None # get parent todo,sub todo by path
|
||||
#self.parent = None
|
||||
self.create_time = time.time()
|
||||
|
||||
self.state = "wait_assign"
|
||||
self.worker = None
|
||||
self.checker = None
|
||||
self.createor = None
|
||||
|
||||
self.need_check = True
|
||||
self.due_date = time.time() + 3600 * 24 * 2
|
||||
self.last_do_time = None
|
||||
self.last_check_time = None
|
||||
self.last_review_time = None
|
||||
|
||||
self.depend_todo_ids = []
|
||||
self.sub_todos = {}
|
||||
|
||||
self.result : AgentTodoResult = None
|
||||
self.last_check_result = None
|
||||
self.retry_count = 0
|
||||
self.raw_obj = None
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls,json_obj:dict) -> 'AgentTodo':
|
||||
todo = AgentTodo()
|
||||
if json_obj.get("id") is not None:
|
||||
todo.todo_id = json_obj.get("id")
|
||||
|
||||
todo.title = json_obj.get("title")
|
||||
todo.state = json_obj.get("state")
|
||||
create_time = json_obj.get("create_time")
|
||||
if create_time:
|
||||
todo.create_time = datetime.fromisoformat(create_time).timestamp()
|
||||
|
||||
todo.detail = json_obj.get("detail")
|
||||
due_date = json_obj.get("due_date")
|
||||
if due_date:
|
||||
todo.due_date = datetime.fromisoformat(due_date).timestamp()
|
||||
|
||||
last_do_time = json_obj.get("last_do_time")
|
||||
if last_do_time:
|
||||
todo.last_do_time = datetime.fromisoformat(last_do_time).timestamp()
|
||||
last_check_time = json_obj.get("last_check_time")
|
||||
if last_check_time:
|
||||
todo.last_check_time = datetime.fromisoformat(last_check_time).timestamp()
|
||||
last_review_time = json_obj.get("last_review_time")
|
||||
if last_review_time:
|
||||
todo.last_review_time = datetime.fromisoformat(last_review_time).timestamp()
|
||||
|
||||
todo.depend_todo_ids = json_obj.get("depend_todo_ids")
|
||||
todo.need_check = json_obj.get("need_check")
|
||||
#todo.result = json_obj.get("result")
|
||||
#todo.last_check_result = json_obj.get("last_check_result")
|
||||
todo.worker = json_obj.get("worker")
|
||||
todo.checker = json_obj.get("checker")
|
||||
todo.createor = json_obj.get("createor")
|
||||
if json_obj.get("retry_count"):
|
||||
todo.retry_count = json_obj.get("retry_count")
|
||||
|
||||
todo.raw_obj = json_obj
|
||||
|
||||
return todo
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
if self.raw_obj:
|
||||
result = self.raw_obj
|
||||
else:
|
||||
result = {}
|
||||
|
||||
result["id"] = self.todo_id
|
||||
#result["parent_id"] = self.parent_id
|
||||
result["title"] = self.title
|
||||
result["state"] = self.state
|
||||
result["create_time"] = datetime.fromtimestamp(self.create_time).isoformat()
|
||||
result["detail"] = self.detail
|
||||
result["due_date"] = datetime.fromtimestamp(self.due_date).isoformat()
|
||||
result["last_do_time"] = datetime.fromtimestamp(self.last_do_time).isoformat() if self.last_do_time else None
|
||||
result["last_check_time"] = datetime.fromtimestamp(self.last_check_time).isoformat() if self.last_check_time else None
|
||||
result["last_review_time"] = datetime.fromtimestamp(self.last_review_time).isoformat() if self.last_review_time else None
|
||||
result["depend_todo_ids"] = self.depend_todo_ids
|
||||
result["need_check"] = self.need_check
|
||||
result["worker"] = self.worker
|
||||
result["checker"] = self.checker
|
||||
result["createor"] = self.createor
|
||||
result["retry_count"] = self.retry_count
|
||||
|
||||
return result
|
||||
|
||||
def to_prompt(self) -> AgentPrompt:
|
||||
json_str = json.dumps(self.raw_obj)
|
||||
return AgentPrompt(json_str)
|
||||
|
||||
def can_review(self) -> bool:
|
||||
if self.state != AgentTodo.TODO_STATE_DONE:
|
||||
return False
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
if self.last_review_time:
|
||||
time_diff = now - self.last_review_time
|
||||
if time_diff < 60*15:
|
||||
logger.info(f"todo {self.title} is already reviewed, ignore")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def can_check(self)->bool:
|
||||
if self.state != AgentTodo.TODO_STATE_WAITING_CHECK:
|
||||
return False
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
if self.last_check_time:
|
||||
time_diff = now - self.last_check_time
|
||||
if time_diff < 60*15:
|
||||
logger.info(f"todo {self.title} is already checked, ignore")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def can_do(self) -> bool:
|
||||
match self.state:
|
||||
case AgentTodo.TODO_STATE_DONE:
|
||||
logger.info(f"todo {self.title} is done, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_CANCEL:
|
||||
logger.info(f"todo {self.title} is cancel, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_EXPIRED:
|
||||
logger.info(f"todo {self.title} is expired, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_EXEC_FAILED:
|
||||
if self.retry_count > 3:
|
||||
logger.info(f"todo {self.title} retry count ({self.retry_count}) is too many, ignore")
|
||||
return False
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
time_diff = self.due_date - now
|
||||
if time_diff < 0:
|
||||
logger.info(f"todo {self.title} is expired, ignore")
|
||||
self.state = AgentTodo.TODO_STATE_EXPIRED
|
||||
return False
|
||||
|
||||
if time_diff > 7*24*3600:
|
||||
logger.info(f"todo {self.title} is far before due date, ignore")
|
||||
return False
|
||||
|
||||
if self.last_do_time:
|
||||
time_diff = now - self.last_do_time
|
||||
if time_diff < 60*15:
|
||||
logger.info(f"todo {self.title} is already do ignore")
|
||||
return False
|
||||
|
||||
logger.info(f"todo {self.title} can do.")
|
||||
return True
|
||||
|
||||
|
||||
class AgentWorkLog:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class BaseAIAgent(abc.ABC):
|
||||
@@ -420,19 +35,9 @@ class BaseAIAgent(abc.ABC):
|
||||
def get_max_token_size(self) -> int:
|
||||
pass
|
||||
|
||||
def token_len(self, text:str=None, prompt:AgentPrompt=None) -> int:
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
if text:
|
||||
return ComputeKernel.llm_num_tokens_from_text(text,self.get_llm_model_name())
|
||||
elif prompt:
|
||||
result = 0
|
||||
if prompt.system_message:
|
||||
result += ComputeKernel.llm_num_tokens_from_text(prompt.system_message.get("content"),self.get_llm_model_name())
|
||||
for msg in prompt.messages:
|
||||
result += ComputeKernel.llm_num_tokens_from_text(msg.get("content"),self.get_llm_model_name())
|
||||
return result
|
||||
else:
|
||||
return 0
|
||||
@abstractmethod
|
||||
async def _process_msg(self,msg:AgentMsg,workspace = None) -> AgentMsg:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_inner_functions(cls, env:BaseEnvironment) -> (dict,int):
|
||||
@@ -458,7 +63,7 @@ class BaseAIAgent(abc.ABC):
|
||||
|
||||
async def do_llm_complection(
|
||||
self,
|
||||
prompt:AgentPrompt,
|
||||
prompt:LLMPrompt,
|
||||
org_msg:AgentMsg=None,
|
||||
env:BaseEnvironment=None,
|
||||
inner_functions=None,
|
||||
@@ -503,7 +108,7 @@ class BaseAIAgent(abc.ABC):
|
||||
inner_func_call_node = result_message.get("function_call")
|
||||
|
||||
if inner_func_call_node:
|
||||
call_prompt : AgentPrompt = copy.deepcopy(prompt)
|
||||
call_prompt : LLMPrompt = copy.deepcopy(prompt)
|
||||
func_msg = copy.deepcopy(result_message)
|
||||
del func_msg["tool_calls"]
|
||||
call_prompt.messages.append(func_msg)
|
||||
@@ -515,7 +120,7 @@ class BaseAIAgent(abc.ABC):
|
||||
self,
|
||||
env: BaseEnvironment,
|
||||
inner_func_call_node: dict,
|
||||
prompt: AgentPrompt,
|
||||
prompt: LLMPrompt,
|
||||
inner_functions: dict,
|
||||
org_msg:AgentMsg,
|
||||
stack_limit = 5
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# TODO: let agent develolp custmized behavior easily
|
||||
class AgentBehavior:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
@@ -0,0 +1,149 @@
|
||||
# Old name is behavior, I belive new name "llm_process" is better
|
||||
from abc import ABC,abstractmethod
|
||||
import copy
|
||||
import json
|
||||
import shlex
|
||||
from typing import Any, Callable, Optional,Dict,Awaitable,List
|
||||
from enum import Enum
|
||||
|
||||
from ..proto.compute_task import *
|
||||
from ..proto.ai_function import *
|
||||
from ..frame.compute_kernel import *
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MIN_PREDICT_TOKEN_LEN = 32
|
||||
|
||||
|
||||
class BaseLLMProcess:
|
||||
def __init__(self) -> None:
|
||||
self.enable_json_resp = False
|
||||
self.model_name = "gpt-4"
|
||||
self.max_token = 2000 # include input prompt
|
||||
self.timeout = 1800 # 30 min
|
||||
|
||||
@abstractmethod
|
||||
async def prepare_prompt(self) -> LLMPrompt:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def _execute_inner_func(self,inner_func_call_node,prompt: LLMPrompt,stack_limit = 5) -> ComputeTaskResult:
|
||||
arguments = None
|
||||
try:
|
||||
func_name = inner_func_call_node.get("name")
|
||||
arguments = json.loads(inner_func_call_node.get("arguments"))
|
||||
logger.info(f"LLMProcess execute inner func:{func_name} :\n\t {json.dumps(arguments)}")
|
||||
|
||||
func_node : AIFunction = await self.get_inner_function(func_name)
|
||||
if func_node is None:
|
||||
result_str:str = f"execute {func_name} error,function not found"
|
||||
else:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
except Exception as e:
|
||||
result_str = f"execute {func_name} error:{str(e)}"
|
||||
logger.error(f"LLMProcess execute inner func:{func_name} error:\n\t{e}")
|
||||
|
||||
logger.info("LLMProcess execute inner func result:" + result_str)
|
||||
|
||||
prompt.messages.append({"role":"function","content":result_str,"name":func_name})
|
||||
if self.enable_json_resp:
|
||||
resp_mode = "json"
|
||||
else:
|
||||
resp_mode = "text"
|
||||
|
||||
max_result_token = self.max_token - ComputeKernel.llm_num_tokens(prompt)
|
||||
if max_result_token < MIN_PREDICT_TOKEN_LEN:
|
||||
task_result = ComputeTaskResult()
|
||||
task_result.result_code = ComputeTaskResultCode.ERROR
|
||||
task_result.error_str = f"prompt too long,can not predict"
|
||||
return task_result
|
||||
|
||||
task_result: ComputeTaskResult = await (ComputeKernel.get_instance().do_llm_completion(
|
||||
prompt,
|
||||
resp_mode=resp_mode,
|
||||
mode_name=self.model_name,
|
||||
max_token=max_result_token,
|
||||
inner_functions=prompt.inner_functions,
|
||||
timeout=self.timeout))
|
||||
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"llm compute error:{task_result.error_str}")
|
||||
return task_result
|
||||
|
||||
inner_func_call_node = None
|
||||
if stack_limit > 0:
|
||||
result_message : dict = task_result.result.get("message")
|
||||
if result_message:
|
||||
inner_func_call_node = result_message.get("function_call")
|
||||
if inner_func_call_node:
|
||||
func_msg = copy.deepcopy(result_message)
|
||||
del func_msg["tool_calls"]#TODO: support tool_calls?
|
||||
prompt.messages.append(func_msg)
|
||||
else:
|
||||
logger.error(f"inner function call stack limit reached")
|
||||
task_result.result_code = ComputeTaskResultCode.ERROR
|
||||
task_result.error_str = "inner function call stack limit reached"
|
||||
return task_result
|
||||
|
||||
if inner_func_call_node:
|
||||
return await self._execute_inner_func(inner_func_call_node,prompt,stack_limit-1)
|
||||
else:
|
||||
return task_result
|
||||
|
||||
async def process(self) -> LLMResult:
|
||||
if self.enable_json_resp:
|
||||
resp_mode = "json"
|
||||
else:
|
||||
resp_mode = "text"
|
||||
|
||||
prompt = await self.prepare_prompt()
|
||||
max_result_token = self.max_token - ComputeKernel.llm_num_tokens(prompt)
|
||||
if max_result_token < MIN_PREDICT_TOKEN_LEN:
|
||||
return LLMResult.from_error_str(f"prompt too long,can not predict")
|
||||
|
||||
task_result: ComputeTaskResult = await (ComputeKernel.get_instance().do_llm_completion(
|
||||
prompt,
|
||||
resp_mode=resp_mode,
|
||||
mode_name=self.model_name,
|
||||
max_token=max_result_token,
|
||||
inner_functions=prompt.inner_functions,
|
||||
timeout=self.timeout))
|
||||
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
err_str = f"do_llm_completion error:{task_result.error_str}"
|
||||
logger.error(err_str)
|
||||
return LLMResult.from_error_str(err_str)
|
||||
|
||||
result_message = task_result.result.get("message")
|
||||
inner_func_call_node = None
|
||||
if result_message:
|
||||
inner_func_call_node = result_message.get("function_call")
|
||||
|
||||
if inner_func_call_node:
|
||||
call_prompt : LLMPrompt = copy.deepcopy(prompt)
|
||||
func_msg = copy.deepcopy(result_message)
|
||||
del func_msg["tool_calls"]
|
||||
call_prompt.messages.append(func_msg)
|
||||
task_result = await self._execute_inner_func(inner_func_call_node,call_prompt)
|
||||
|
||||
# parse task_result to LLM Result
|
||||
if self.enable_json_resp:
|
||||
llm_result = LLMResult.from_json_str(task_result.result_str)
|
||||
else:
|
||||
llm_result = LLMResult.from_str(task_result.result_str)
|
||||
|
||||
# execute op_list in LLM Result?
|
||||
|
||||
return llm_result
|
||||
|
||||
#class LLMProcess
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
|
||||
from .agent_base import AgentPrompt
|
||||
from .agent_base import LLMPrompt
|
||||
|
||||
class AIRole:
|
||||
def __init__(self) -> None:
|
||||
@@ -9,7 +9,7 @@ class AIRole:
|
||||
self.role_id :str = None # $workflow_id.$sub_workflow_id.$role_name
|
||||
self.fullname : str = None
|
||||
self.agent_name : str = None
|
||||
self.prompt : AgentPrompt = None
|
||||
self.prompt : LLMPrompt = None
|
||||
self.introduce : str = None
|
||||
self.agent = None
|
||||
self.enable_function_list : list[str] = None
|
||||
@@ -31,7 +31,7 @@ class AIRole:
|
||||
|
||||
prompt_node = config.get("prompt")
|
||||
if prompt_node:
|
||||
self.prompt = AgentPrompt()
|
||||
self.prompt = LLMPrompt()
|
||||
if self.prompt.load_from_config(prompt_node) is False:
|
||||
logging.error("load prompt failed!")
|
||||
return False
|
||||
@@ -56,7 +56,7 @@ class AIRole:
|
||||
def get_name(self) -> str:
|
||||
return self.role_name
|
||||
|
||||
def get_prompt(self) -> AgentPrompt:
|
||||
def get_prompt(self) -> LLMPrompt:
|
||||
return self.prompt
|
||||
|
||||
class AIRoleGroup:
|
||||
|
||||
+15
-15
@@ -9,11 +9,11 @@ from abc import ABC, abstractmethod
|
||||
|
||||
from ..proto.compute_task import *
|
||||
from ..proto.agent_msg import *
|
||||
from ..proto.ai_function import *
|
||||
|
||||
from .agent_base import *
|
||||
from .chatsession import AIChatSession
|
||||
from .role import AIRole,AIRoleGroup
|
||||
from .ai_function import AIFunction,FunctionItem
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..frame.bus import AIBus
|
||||
@@ -48,7 +48,7 @@ class Workflow:
|
||||
def __init__(self) -> None:
|
||||
self.workflow_name : str = None
|
||||
self.workflow_id : str = None
|
||||
self.rule_prompt : AgentPrompt = None
|
||||
self.rule_prompt : LLMPrompt = None
|
||||
self.workflow_config = None
|
||||
self.role_group : dict = None
|
||||
self.input_filter : MessageFilter= None
|
||||
@@ -83,7 +83,7 @@ class Workflow:
|
||||
self.db_file = self.owner_workflow.db_file
|
||||
|
||||
if config.get("prompt") is not None:
|
||||
self.rule_prompt = AgentPrompt()
|
||||
self.rule_prompt = LLMPrompt()
|
||||
if self.rule_prompt.load_from_config(config.get("prompt")) is False:
|
||||
logger.error("Workflow load prompt failed")
|
||||
return False
|
||||
@@ -279,7 +279,7 @@ class Workflow:
|
||||
logger.info(f"{msg.sender} post message {msg.msg_id} to AIBus: {msg.target}")
|
||||
return await self.get_bus().send_message(msg)
|
||||
|
||||
async def role_call(self,func_item:FunctionItem,the_role:AIRole):
|
||||
async def role_call(self,func_item:ActionItem,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} call {func_item.name} ")
|
||||
arguments = func_item.args
|
||||
|
||||
@@ -290,11 +290,11 @@ class Workflow:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
return result_str
|
||||
|
||||
async def role_post_call(self,func_item:FunctionItem,the_role:AIRole):
|
||||
async def role_post_call(self,func_item:ActionItem,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} post call {func_item.name} ")
|
||||
return await self.role_call(func_item,the_role)
|
||||
|
||||
def _format_msg_by_env_value(self,prompt:AgentPrompt):
|
||||
def _format_msg_by_env_value(self,prompt:LLMPrompt):
|
||||
if self.workflow_env is None:
|
||||
return
|
||||
|
||||
@@ -326,7 +326,7 @@ class Workflow:
|
||||
return result_func
|
||||
return None
|
||||
|
||||
async def _role_execute_func(self,the_role:AIRole,inenr_func_call_node:dict,prompt:AgentPrompt,org_msg:AgentMsg,stack_limit = 5) -> [str,int]:
|
||||
async def _role_execute_func(self,the_role:AIRole,inenr_func_call_node:dict,prompt:LLMPrompt,org_msg:AgentMsg,stack_limit = 5) -> [str,int]:
|
||||
|
||||
func_name = inenr_func_call_node.get("name")
|
||||
arguments = json.loads(inenr_func_call_node.get("arguments"))
|
||||
@@ -372,7 +372,7 @@ class Workflow:
|
||||
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole,workflow_chat_session:AIChatSession) -> AgentMsg:
|
||||
msg.target = the_role.get_role_id()
|
||||
|
||||
prompt = AgentPrompt()
|
||||
prompt = LLMPrompt()
|
||||
prompt.append(the_role.agent.agent_prompt)
|
||||
prompt.append(self.get_workflow_rule_prompt())
|
||||
prompt.append(the_role.get_prompt())
|
||||
@@ -382,7 +382,7 @@ class Workflow:
|
||||
#support group chat, user content include sender name!
|
||||
prompt.append(await self._get_prompt_from_session(the_role,workflow_chat_session))
|
||||
|
||||
msg_prompt = AgentPrompt()
|
||||
msg_prompt = LLMPrompt()
|
||||
msg_prompt.messages = [{"role":"user","content":f"user name is {msg.sender}, his question is :{msg.body}"}]
|
||||
prompt.append(msg_prompt)
|
||||
|
||||
@@ -461,20 +461,20 @@ class Workflow:
|
||||
# message will be saved in role.process_message
|
||||
pass
|
||||
|
||||
this_llm_resp_prompt = AgentPrompt()
|
||||
this_llm_resp_prompt = LLMPrompt()
|
||||
this_llm_resp_prompt.messages = [{"role":"assistant","content":result_str}]
|
||||
prompt.append(this_llm_resp_prompt)
|
||||
|
||||
result_prompt = AgentPrompt()
|
||||
result_prompt = LLMPrompt()
|
||||
result_prompt.messages = [{"role":"user","content":result_prompt_str}]
|
||||
prompt.append(result_prompt)
|
||||
return await _do_process_msg()
|
||||
|
||||
return await _do_process_msg()
|
||||
|
||||
async def _get_prompt_from_session(self,the_role:AIRole,chatsession:AIChatSession) -> AgentPrompt:
|
||||
async def _get_prompt_from_session(self,the_role:AIRole,chatsession:AIChatSession) -> LLMPrompt:
|
||||
messages = chatsession.read_history(the_role.history_len) # read last 10 message
|
||||
result_prompt = AgentPrompt()
|
||||
result_prompt = LLMPrompt()
|
||||
|
||||
for msg in reversed(messages):
|
||||
if msg.sender == the_role.role_id:
|
||||
@@ -484,10 +484,10 @@ class Workflow:
|
||||
|
||||
return result_prompt
|
||||
|
||||
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
||||
def _get_knowlege_prompt(self,role_name:str) -> LLMPrompt:
|
||||
pass
|
||||
|
||||
def get_workflow_rule_prompt(self) -> AgentPrompt:
|
||||
def get_workflow_rule_prompt(self) -> LLMPrompt:
|
||||
return self.rule_prompt
|
||||
|
||||
# def _env_event_to_msg(self,env_event:EnvironmentEvent) -> AgentMsg:
|
||||
|
||||
@@ -2,7 +2,7 @@ import logging
|
||||
from typing import Dict
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Dict
|
||||
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
from .code_interpreter import execute_code
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
from typing import Dict
|
||||
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
from duckduckgo_search import AsyncDDGS
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Callable, Optional,Dict,Awaitable,List
|
||||
import logging
|
||||
from ..agent.ai_function import AIFunction, AIOperation
|
||||
from ..proto.ai_function import *
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -2,7 +2,7 @@ import logging
|
||||
from typing import Dict
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import random
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..storage.storage import AIStorage
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Dict
|
||||
|
||||
from cachetools import TLRUCache, cached
|
||||
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
from .sql_database import SQLDatabase, get_from_env
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import random
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
from ..agent.ai_function import AIFunction
|
||||
from ..proto.ai_function import *
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..storage.storage import AIStorage
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import Optional
|
||||
import aiosqlite
|
||||
|
||||
from ..proto.compute_task import *
|
||||
from ..agent.ai_function import SimpleAIFunction
|
||||
from ..proto.ai_function import *
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..frame.contact_manager import ContactManager,Contact,FamilyMember
|
||||
from ..storage.storage import AIStorage
|
||||
@@ -302,7 +302,7 @@ class CalenderEnvironment(SimpleEnvironment):
|
||||
return f'exec paint OK, saved as a local file, path is: {result.result["file"]}'
|
||||
|
||||
|
||||
class PaintEnvironment(BaseEnvironment):
|
||||
class PaintEnvironment(SimpleEnvironment):
|
||||
def __init__(self, env_id: str) -> None:
|
||||
super().__init__(env_id)
|
||||
self.is_run = False
|
||||
|
||||
@@ -6,8 +6,12 @@ import sqlite3
|
||||
import asyncio
|
||||
from typing import Any,List,Dict
|
||||
import chardet
|
||||
from ..agent.agent_base import AgentMsg,AgentTodo,AgentPrompt,AgentTodoResult
|
||||
from ..agent.ai_function import AIFunction,SimpleAIFunction, SimpleAIOperation
|
||||
|
||||
from ..proto.agent_task import *
|
||||
from ..proto.ai_function import *
|
||||
from ..proto.compute_task import *
|
||||
from ..agent.agent_base import *
|
||||
|
||||
from ..storage.storage import AIStorage,ResourceLocation
|
||||
from .environment import SimpleEnvironment, CompositeEnvironment
|
||||
|
||||
@@ -289,16 +293,16 @@ class WorkspaceEnvironment(CompositeEnvironment):
|
||||
def get_prompt(self) -> AgentMsg:
|
||||
return None
|
||||
|
||||
def get_role_prompt(self,role_id:str) -> AgentPrompt:
|
||||
def get_role_prompt(self,role_id:str) -> LLMPrompt:
|
||||
return None
|
||||
|
||||
def get_do_prompt(self,todo:AgentTodo=None)->AgentPrompt:
|
||||
def get_do_prompt(self,todo:AgentTodo=None)->LLMPrompt:
|
||||
return None
|
||||
|
||||
# result mean: list[op_error_str],have_error
|
||||
async def exec_op_list(self,oplist:List,agent_id:str)->tuple[List[str],bool]:
|
||||
result_str = "op list is none"
|
||||
if oplist is None:
|
||||
if oplist is None or len(oplist) == 0:
|
||||
return None,False
|
||||
|
||||
result_str = []
|
||||
|
||||
@@ -8,7 +8,7 @@ from asyncio import Queue
|
||||
|
||||
from ..proto.compute_task import *
|
||||
from ..knowledge import ObjectID
|
||||
from ..agent.agent_base import AgentPrompt
|
||||
|
||||
from .compute_node import ComputeNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -106,6 +106,9 @@ class ComputeKernel:
|
||||
|
||||
@staticmethod
|
||||
def llm_num_tokens_from_text(text:str,model:str) -> int:
|
||||
if model is None:
|
||||
model = "gpt4"
|
||||
|
||||
try:
|
||||
encoding = tiktoken.encoding_for_model(model)
|
||||
except KeyError:
|
||||
@@ -115,9 +118,12 @@ class ComputeKernel:
|
||||
token_count = len(encoding.encode(text))
|
||||
return token_count
|
||||
|
||||
@staticmethod
|
||||
def llm_num_tokens(prompt: LLMPrompt, model_name: str = None) -> int:
|
||||
return ComputeKernel.llm_num_tokens_from_text(prompt.as_str(), model_name)
|
||||
|
||||
# friendly interface for use:
|
||||
def llm_completion(self, prompt: AgentPrompt, resp_mode:str="text",mode_name: Optional[str] = None, max_token: int = 0,inner_functions = None):
|
||||
def llm_completion(self, prompt: LLMPrompt, resp_mode:str="text",mode_name: Optional[str] = None, max_token: int = 0,inner_functions = None):
|
||||
# craete a llm_work_task ,push on queue's end
|
||||
# then task_schedule would run this task.(might schedule some work_task to another host)
|
||||
task_req = ComputeTask()
|
||||
@@ -153,7 +159,7 @@ class ComputeKernel:
|
||||
return time_out_result
|
||||
|
||||
|
||||
async def do_llm_completion(self, prompt: AgentPrompt,resp_mode:str="text", mode_name: Optional[str]=None, max_token:int=0, inner_functions=None, timeout=60) -> str:
|
||||
async def do_llm_completion(self, prompt: LLMPrompt,resp_mode:str="text", mode_name: Optional[str]=None, max_token:int=0, inner_functions=None, timeout=60) -> str:
|
||||
task_req = self.llm_completion(prompt, resp_mode,mode_name, max_token,inner_functions)
|
||||
return await self._wait_task(task_req, timeout)
|
||||
|
||||
|
||||
@@ -232,9 +232,4 @@ class AgentMsg:
|
||||
def get_quote_msg_id(self) -> str:
|
||||
return self.quote_msg_id
|
||||
|
||||
@classmethod
|
||||
def parse_function_call(cls,func_string:str):
|
||||
str_list = shlex.split(func_string)
|
||||
func_name = str_list[0]
|
||||
params = str_list[1:]
|
||||
return func_name, params
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from anyio import Path
|
||||
|
||||
|
||||
class AgentTodoResult:
|
||||
TODO_RESULT_CODE_OK = 0,
|
||||
TODO_RESULT_CODE_LLM_ERROR = 1,
|
||||
TODO_RESULT_CODE_EXEC_OP_ERROR = 2
|
||||
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.result_code = AgentTodoResult.TODO_RESULT_CODE_OK
|
||||
self.result_str = None
|
||||
self.error_str = None
|
||||
self.op_list = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
result = {}
|
||||
result["result_code"] = self.result_code
|
||||
result["result_str"] = self.result_str
|
||||
result["error_str"] = self.error_str
|
||||
result["op_list"] = self.op_list
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
class AgentTodo:
|
||||
TODO_STATE_WAIT_ASSIGN = "wait_assign"
|
||||
TODO_STATE_INIT = "init"
|
||||
|
||||
TODO_STATE_PENDING = "pending"
|
||||
TODO_STATE_WAITING_CHECK = "wait_check"
|
||||
TODO_STATE_EXEC_FAILED = "exec_failed"
|
||||
TDDO_STATE_CHECKFAILED = "check_failed"
|
||||
|
||||
TODO_STATE_CASNCEL = "cancel"
|
||||
TODO_STATE_DONE = "done"
|
||||
TODO_STATE_EXPIRED = "expired"
|
||||
|
||||
def __init__(self):
|
||||
self.todo_id = "todo#" + uuid.uuid4().hex
|
||||
self.title = None
|
||||
self.detail = None
|
||||
self.todo_path = None # get parent todo,sub todo by path
|
||||
#self.parent = None
|
||||
self.create_time = time.time()
|
||||
|
||||
self.state = "wait_assign"
|
||||
self.worker = None
|
||||
self.checker = None
|
||||
self.createor = None
|
||||
|
||||
self.need_check = True
|
||||
self.due_date = time.time() + 3600 * 24 * 2
|
||||
self.last_do_time = None
|
||||
self.last_check_time = None
|
||||
self.last_review_time = None
|
||||
|
||||
self.depend_todo_ids = []
|
||||
self.sub_todos = {}
|
||||
|
||||
self.result : AgentTodoResult = None
|
||||
self.last_check_result = None
|
||||
self.retry_count = 0
|
||||
self.raw_obj = None
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls,json_obj:dict) -> 'AgentTodo':
|
||||
todo = AgentTodo()
|
||||
if json_obj.get("id") is not None:
|
||||
todo.todo_id = json_obj.get("id")
|
||||
|
||||
todo.title = json_obj.get("title")
|
||||
todo.state = json_obj.get("state")
|
||||
create_time = json_obj.get("create_time")
|
||||
if create_time:
|
||||
todo.create_time = datetime.fromisoformat(create_time).timestamp()
|
||||
|
||||
todo.detail = json_obj.get("detail")
|
||||
due_date = json_obj.get("due_date")
|
||||
if due_date:
|
||||
todo.due_date = datetime.fromisoformat(due_date).timestamp()
|
||||
|
||||
last_do_time = json_obj.get("last_do_time")
|
||||
if last_do_time:
|
||||
todo.last_do_time = datetime.fromisoformat(last_do_time).timestamp()
|
||||
last_check_time = json_obj.get("last_check_time")
|
||||
if last_check_time:
|
||||
todo.last_check_time = datetime.fromisoformat(last_check_time).timestamp()
|
||||
last_review_time = json_obj.get("last_review_time")
|
||||
if last_review_time:
|
||||
todo.last_review_time = datetime.fromisoformat(last_review_time).timestamp()
|
||||
|
||||
todo.depend_todo_ids = json_obj.get("depend_todo_ids")
|
||||
todo.need_check = json_obj.get("need_check")
|
||||
#todo.result = json_obj.get("result")
|
||||
#todo.last_check_result = json_obj.get("last_check_result")
|
||||
todo.worker = json_obj.get("worker")
|
||||
todo.checker = json_obj.get("checker")
|
||||
todo.createor = json_obj.get("createor")
|
||||
if json_obj.get("retry_count"):
|
||||
todo.retry_count = json_obj.get("retry_count")
|
||||
|
||||
todo.raw_obj = json_obj
|
||||
|
||||
return todo
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
if self.raw_obj:
|
||||
result = self.raw_obj
|
||||
else:
|
||||
result = {}
|
||||
|
||||
result["id"] = self.todo_id
|
||||
#result["parent_id"] = self.parent_id
|
||||
result["title"] = self.title
|
||||
result["state"] = self.state
|
||||
result["create_time"] = datetime.fromtimestamp(self.create_time).isoformat()
|
||||
result["detail"] = self.detail
|
||||
result["due_date"] = datetime.fromtimestamp(self.due_date).isoformat()
|
||||
result["last_do_time"] = datetime.fromtimestamp(self.last_do_time).isoformat() if self.last_do_time else None
|
||||
result["last_check_time"] = datetime.fromtimestamp(self.last_check_time).isoformat() if self.last_check_time else None
|
||||
result["last_review_time"] = datetime.fromtimestamp(self.last_review_time).isoformat() if self.last_review_time else None
|
||||
result["depend_todo_ids"] = self.depend_todo_ids
|
||||
result["need_check"] = self.need_check
|
||||
result["worker"] = self.worker
|
||||
result["checker"] = self.checker
|
||||
result["createor"] = self.createor
|
||||
result["retry_count"] = self.retry_count
|
||||
|
||||
return result
|
||||
|
||||
def can_check(self)->bool:
|
||||
if self.state != AgentTodo.TODO_STATE_WAITING_CHECK:
|
||||
return False
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
if self.last_check_time:
|
||||
time_diff = now - self.last_check_time
|
||||
if time_diff < 60*15:
|
||||
logger.info(f"todo {self.title} is already checked, ignore")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def can_do(self) -> bool:
|
||||
match self.state:
|
||||
case AgentTodo.TODO_STATE_DONE:
|
||||
logger.info(f"todo {self.title} is done, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_CASNCEL:
|
||||
logger.info(f"todo {self.title} is cancel, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_EXPIRED:
|
||||
logger.info(f"todo {self.title} is expired, ignore")
|
||||
return False
|
||||
case AgentTodo.TODO_STATE_EXEC_FAILED:
|
||||
if self.retry_count > 3:
|
||||
logger.info(f"todo {self.title} retry count ({self.retry_count}) is too many, ignore")
|
||||
return False
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
time_diff = self.due_date - now
|
||||
if time_diff < 0:
|
||||
logger.info(f"todo {self.title} is expired, ignore")
|
||||
self.state = AgentTodo.TODO_STATE_EXPIRED
|
||||
return False
|
||||
|
||||
if time_diff > 7*24*3600:
|
||||
logger.info(f"todo {self.title} is far before due date, ignore")
|
||||
return False
|
||||
|
||||
if self.last_do_time:
|
||||
time_diff = now - self.last_do_time
|
||||
if time_diff < 60*15:
|
||||
logger.info(f"todo {self.title} is already do ignore")
|
||||
return False
|
||||
|
||||
logger.info(f"todo {self.title} can do.")
|
||||
return True
|
||||
|
||||
class AgentTask:
|
||||
def __init__(self) -> None:
|
||||
self.task_id : str = "task#" + uuid.uuid4().hex
|
||||
self.task_path : Path = None # get parent todo,sub todo by path
|
||||
self.title = None
|
||||
self.detail = None
|
||||
|
||||
self.create_time = time.time()
|
||||
|
||||
self.state = "wait_assign"
|
||||
self.worker = None
|
||||
self.createor = None
|
||||
|
||||
self.due_date = time.time() + 3600 * 24 * 2
|
||||
self.depend_task_ids = []
|
||||
self.step_todos = {}
|
||||
|
||||
self.last_plan_time = None
|
||||
self.last_check_time = None
|
||||
#self.last_review_time = None
|
||||
|
||||
self.result : LLMResult = None
|
||||
self.last_check_result = None
|
||||
self.retry_count = 0
|
||||
self.raw_obj = None
|
||||
|
||||
|
||||
|
||||
class AgentWorkLog:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class AgentReport:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
@@ -73,7 +73,7 @@ class AIFunction:
|
||||
#def load_from_config(self,config:dict) -> bool:
|
||||
# pass
|
||||
|
||||
class FunctionItem:
|
||||
class ActionItem:
|
||||
def __init__(self,name,args) -> None:
|
||||
self.name = name
|
||||
self.args = args
|
||||
@@ -1,11 +1,20 @@
|
||||
|
||||
import copy
|
||||
from enum import Enum
|
||||
import json
|
||||
import shlex
|
||||
import uuid
|
||||
import time
|
||||
from typing import Union
|
||||
from typing import List, Union
|
||||
from ..proto.ai_function import *
|
||||
from ..knowledge import ObjectID
|
||||
from ..storage.storage import AIStorage
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ComputeTaskResultCode(Enum):
|
||||
OK = 0
|
||||
TIMEOUT = 1
|
||||
@@ -31,6 +40,164 @@ class ComputeTaskType(Enum):
|
||||
TEXT_EMBEDDING ="text_embedding"
|
||||
IMAGE_EMBEDDING ="image_embedding"
|
||||
|
||||
class LLMPrompt:
|
||||
def __init__(self,prompt_str = None) -> None:
|
||||
self.messages = []
|
||||
if prompt_str:
|
||||
self.messages.append({"role":"user","content":prompt_str})
|
||||
self.system_message = None
|
||||
|
||||
def as_str(self)->str:
|
||||
result_str = ""
|
||||
if self.system_message:
|
||||
result_str += self.system_message.get("role") + ":" + self.system_message.get("content") + "\n"
|
||||
if self.messages:
|
||||
for msg in self.messages:
|
||||
result_str += msg.get("role") + ":" + msg.get("content") + "\n"
|
||||
|
||||
return result_str
|
||||
|
||||
def to_message_list(self):
|
||||
result = []
|
||||
if self.system_message:
|
||||
result.append(self.system_message)
|
||||
result.extend(self.messages)
|
||||
return result
|
||||
|
||||
def append(self,prompt:'LLMPrompt'):
|
||||
if prompt is None:
|
||||
return
|
||||
|
||||
if prompt.system_message is not None:
|
||||
if self.system_message is None:
|
||||
self.system_message = copy.deepcopy(prompt.system_message)
|
||||
else:
|
||||
self.system_message["content"] += prompt.system_message.get("content")
|
||||
|
||||
self.messages.extend(prompt.messages)
|
||||
|
||||
def load_from_config(self,config:list) -> bool:
|
||||
if isinstance(config,list) is not True:
|
||||
logger.error("prompt is not list!")
|
||||
return False
|
||||
self.messages = []
|
||||
for msg in config:
|
||||
if msg.get("content"):
|
||||
if msg.get("role") == "system":
|
||||
self.system_message = msg
|
||||
else:
|
||||
self.messages.append(msg)
|
||||
else:
|
||||
logger.error("prompt message has no content!")
|
||||
return True
|
||||
|
||||
|
||||
class LLMResultStates(Enum):
|
||||
IGNORE = "ignore"
|
||||
OK = "ok" # process done
|
||||
ERROR = "error"
|
||||
|
||||
class LLMResult:
|
||||
def __init__(self) -> None:
|
||||
self.state : str = LLMResultStates.IGNORE
|
||||
self.compute_error_str = None
|
||||
self.resp : str = "" # llm say:
|
||||
self.raw_result = None # raw result from compute kernel
|
||||
self.inner_functions : List[AIFunction] = []
|
||||
self.action_list : List[ActionItem] = [] # op_list is a optimize design for saving token
|
||||
|
||||
#self.post_msgs : List[AgentMsg] = [] # move to op_list
|
||||
# self.send_msgs : List[AgentMsg] = [] # move to op_list
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_error_str(self,error_str:str) -> 'LLMResult':
|
||||
r = LLMResult()
|
||||
r.state = "error"
|
||||
r.compute_error_str = error_str
|
||||
return r
|
||||
|
||||
@classmethod
|
||||
def from_json_str(self,llm_json_str:str) -> 'LLMResult':
|
||||
r = LLMResult()
|
||||
if llm_json_str is None:
|
||||
r.state = LLMResultStates.IGNORE
|
||||
return r
|
||||
if llm_json_str == "**IGNORE**":
|
||||
r.state = LLMResultStates.IGNORE
|
||||
return r
|
||||
|
||||
llm_json = json.loads(llm_json_str)
|
||||
r.resp = llm_json.get("resp")
|
||||
r.raw_result = llm_json
|
||||
r.action_list = llm_json.get("actions")
|
||||
|
||||
return r
|
||||
|
||||
@classmethod
|
||||
def parse_action(cls,func_string:str):
|
||||
str_list = shlex.split(func_string)
|
||||
func_name = str_list[0]
|
||||
params = str_list[1:]
|
||||
return func_name, params
|
||||
|
||||
@classmethod
|
||||
def from_str(self,llm_result_str:str,valid_func:List[str]=None) -> 'LLMResult':
|
||||
r = LLMResult()
|
||||
|
||||
if llm_result_str is None:
|
||||
r.state = LLMResultStates.IGNORE
|
||||
return r
|
||||
if llm_result_str == "**IGNORE**":
|
||||
r.state = LLMResultStates.IGNORE
|
||||
return r
|
||||
|
||||
if llm_result_str[0] == "{":
|
||||
return LLMResult.from_json_str(llm_result_str)
|
||||
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
|
||||
def check_args(action_item:ActionItem):
|
||||
match action_item.name:
|
||||
case "post_msg":# /post_msg $target_id
|
||||
if len(action_item.args) != 1:
|
||||
return False
|
||||
|
||||
new_msg = AgentMsg()
|
||||
target_id = action_item.args[0]
|
||||
msg_content = action_item.body
|
||||
new_msg.set("",target_id,msg_content)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
current_action : ActionItem = None
|
||||
for line in lines:
|
||||
if line.startswith("##/"):
|
||||
if current_action:
|
||||
if check_args(current_action) is False:
|
||||
r.resp += current_action.dumps()
|
||||
else:
|
||||
r.action_list.append(current_action)
|
||||
|
||||
action_name,action_args = LLMResult.parse_action(line[3:])
|
||||
current_action = ActionItem(action_name,action_args)
|
||||
else:
|
||||
if current_action:
|
||||
current_action.append_body(line + "\n")
|
||||
else:
|
||||
r.resp += line + "\n"
|
||||
|
||||
if current_action:
|
||||
if check_args(current_action) is False:
|
||||
r.resp += current_action.dumps()
|
||||
else:
|
||||
r.action_list.append(current_action)
|
||||
return r
|
||||
|
||||
class ComputeTask:
|
||||
def __init__(self) -> None:
|
||||
@@ -140,3 +307,5 @@ class ComputeTaskResult:
|
||||
self.task_id = task.task_id
|
||||
self.callchain_id = task.callchain_id
|
||||
task.result = self
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user