read mail with issue tree pipeline works

This commit is contained in:
tsukasa
2023-11-20 22:01:18 +08:00
parent 9c00187041
commit a63e9b6745
12 changed files with 215 additions and 140 deletions
@@ -5,5 +5,9 @@ input.params.watch = true
parser.module = "parser.py" parser.module = "parser.py"
parser.params.mail_path = "${myai_dir}/mail" parser.params.mail_path = "${myai_dir}/mail"
parser.params.issue_path = "${myai_dir}/mail/issue.json" parser.params.issue_path = "${myai_dir}/mail/issue.json"
parser.params.root_issue = "巴克云公司推进中的项目" [parser.params.root_issue]
summary = "巴克云公司推进中的项目"
[[parser.params.root_issue.children]]
summary = "去中心存储项目DMC"
+12 -8
View File
@@ -14,6 +14,7 @@ import sys
from .agent_base import AgentMsg, AgentMsgStatus, AgentMsgType, FunctionItem, LLMResult, AgentPrompt, AgentReport, \ from .agent_base import AgentMsg, AgentMsgStatus, AgentMsgType, FunctionItem, LLMResult, AgentPrompt, AgentReport, \
AgentTodo, AgentTodoResult, AgentWorkLog, BaseAIAgent AgentTodo, AgentTodoResult, AgentWorkLog, BaseAIAgent
from .chatsession import AIChatSession from .chatsession import AIChatSession
from .compute_task import ComputeTaskResult,ComputeTaskResultCode from .compute_task import ComputeTaskResult,ComputeTaskResultCode
from .ai_function import AIFunction from .ai_function import AIFunction
@@ -287,6 +288,7 @@ class AIAgent(BaseAIAgent):
return None return None
def _get_inner_functions(self) -> dict: def _get_inner_functions(self) -> dict:
if self.owner_env is None: if self.owner_env is None:
return None,0 return None,0
@@ -357,6 +359,7 @@ class AIAgent(BaseAIAgent):
else: else:
return task_result return task_result
def get_agent_prompt(self) -> AgentPrompt: def get_agent_prompt(self) -> AgentPrompt:
return self.agent_prompt return self.agent_prompt
@@ -520,7 +523,7 @@ class AIAgent(BaseAIAgent):
if todo_count > 0: if todo_count > 0:
have_known_info = True have_known_info = True
known_info_str += f"## todo\n{todos_str}\n" known_info_str += f"## todo\n{todos_str}\n"
inner_functions,function_token_len = self._get_inner_functions() inner_functions,function_token_len = BaseAIAgent.get_inner_functions(self.owner_env)
system_prompt_len = prompt.get_prompt_token_len() system_prompt_len = prompt.get_prompt_token_len()
input_len = len(msg.body) input_len = len(msg.body)
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG: if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
@@ -540,7 +543,7 @@ class AIAgent(BaseAIAgent):
logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ") logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
#task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions) #task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
task_result = await self._do_llm_complection(prompt,inner_functions,msg) task_result = await self._do_llm_complection(prompt,msg,inner_functions=inner_functions)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
error_resp = msg.create_error_resp(task_result.error_str) error_resp = msg.create_error_resp(task_result.error_str)
return error_resp return error_resp
@@ -778,9 +781,9 @@ class AIAgent(BaseAIAgent):
todo_tree = workspace.get_todo_tree("/") todo_tree = workspace.get_todo_tree("/")
prompt.append(AgentPrompt(todo_tree)) prompt.append(AgentPrompt(todo_tree))
inner_functions,function_token_len = self._get_inner_functions() inner_functions,_ = BaseAIAgent.get_inner_functions(self.owner_env)
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,inner_functions) task_result:ComputeTaskResult = await self._do_llm_complection(prompt,inner_functions=inner_functions)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"_llm_review_todos compute error:{task_result.error_str}") logger.error(f"_llm_review_todos compute error:{task_result.error_str}")
return return
@@ -897,7 +900,8 @@ class AIAgent(BaseAIAgent):
prompt.append(todo.detail) prompt.append(todo.detail)
prompt.append(todo.result) prompt.append(todo.result)
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,workspace.get_inner_functions(),None,True) inner_functions,_ = BaseAIAgent.get_inner_functions(workspace)
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,inner_functions=inner_functions,is_json_resp=True)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"_llm_check_todo compute error:{task_result.error_str}") logger.error(f"_llm_check_todo compute error:{task_result.error_str}")
@@ -1058,7 +1062,7 @@ class AIAgent(BaseAIAgent):
prompt.append(content_prompt) prompt.append(content_prompt)
env_functions = None env_functions = None
#env_functions,function_len = workspace.get_knowledge_base_ai_functions() #env_functions,function_len = workspace.get_knowledge_base_ai_functions()
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,env_functions,None,True) task_result:ComputeTaskResult = await self._do_llm_complection(prompt,is_json_resp=True)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
result_obj = {} result_obj = {}
result_obj["error_str"] = task_result.error_str result_obj["error_str"] = task_result.error_str
@@ -1091,9 +1095,8 @@ class AIAgent(BaseAIAgent):
prompt.append(known_info_prompt) prompt.append(known_info_prompt)
content_prompt = AgentPrompt(part_content) content_prompt = AgentPrompt(part_content)
prompt.append(content_prompt) prompt.append(content_prompt)
env_functions = None
#env_functions,function_len = workspace.get_knowledge_base_ai_functions() #env_functions,function_len = workspace.get_knowledge_base_ai_functions()
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,env_functions,None,True) task_result:ComputeTaskResult = await self._do_llm_complection(prompt,is_json_resp=True)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
result_obj = {} result_obj = {}
result_obj["error_str"] = task_result.error_str result_obj["error_str"] = task_result.error_str
@@ -1222,6 +1225,7 @@ class AIAgent(BaseAIAgent):
return task_result return task_result
def need_work(self) -> bool: def need_work(self) -> bool:
if self.do_prompt is not None: if self.do_prompt is not None:
return True return True
+14 -8
View File
@@ -600,7 +600,7 @@ class BaseAIAgent:
pass pass
@classmethod @classmethod
def _get_inner_functions(cls, env:Environment) -> (dict,int): def get_inner_functions(cls, env:Environment) -> (dict,int):
if env is None: if env is None:
return None,0 return None,0
@@ -624,18 +624,24 @@ class BaseAIAgent:
@classmethod @classmethod
async def do_llm_complection( async def do_llm_complection(
cls, cls,
env:Environment,
prompt:AgentPrompt, prompt:AgentPrompt,
org_msg:AgentMsg,
llm_model_name:str, llm_model_name:str,
max_token_size:int max_token_size:int,
org_msg:AgentMsg=None,
env:Environment=None,
inner_functions=None,
is_json_resp=False,
) -> ComputeTaskResult: ) -> ComputeTaskResult:
from .compute_kernel import ComputeKernel from .compute_kernel import ComputeKernel
#logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ") #logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
inner_functions,inner_functions_len = cls._get_inner_functions(env) if inner_functions is None and env is not None:
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,llm_model_name,max_token_size,inner_functions) inner_functions,_ = cls.get_inner_functions(env)
if is_json_resp:
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,"json",llm_model_name,max_token_size,inner_functions,timeout=None)
else:
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,"text",llm_model_name,max_token_size,inner_functions,timeout=None)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"llm compute error:{task_result.error_str}") logger.error(f"_do_llm_complection llm compute error:{task_result.error_str}")
#error_resp = msg.create_error_resp(task_result.error_str) #error_resp = msg.create_error_resp(task_result.error_str)
return task_result return task_result
@@ -649,7 +655,7 @@ class BaseAIAgent:
task_result = await cls._execute_func(env,inner_func_call_node,call_prompt,inner_functions,org_msg,llm_model_name,max_token_size) task_result = await cls._execute_func(env,inner_func_call_node,call_prompt,inner_functions,org_msg,llm_model_name,max_token_size)
return task_result return task_result
@classmethod @classmethod
async def _execute_func( async def _execute_func(
cls, cls,
+5 -5
View File
@@ -127,7 +127,7 @@ class ComputeKernel:
self.run(task_req) self.run(task_req)
return task_req return task_req
async def _wait_task(self,task_req:ComputeTask)->ComputeTaskResult: async def _wait_task(self,task_req:ComputeTask, timeout=60)->ComputeTaskResult:
async def check_timer(): async def check_timer():
check_times = 0 check_times = 0
while True: while True:
@@ -136,8 +136,8 @@ class ComputeKernel:
if task_req.state == ComputeTaskState.ERROR: if task_req.state == ComputeTaskState.ERROR:
break break
if check_times >= 120: if timeout is not None and check_times >= timeout*2:
task_req.state = ComputeTaskState.ERROR task_req.state = ComputeTaskState.ERROR
break break
@@ -155,9 +155,9 @@ class ComputeKernel:
return time_out_result 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) -> str: 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:
task_req = self.llm_completion(prompt, resp_mode,mode_name, max_token,inner_functions) task_req = self.llm_completion(prompt, resp_mode,mode_name, max_token,inner_functions)
return await self._wait_task(task_req) return await self._wait_task(task_req, timeout)
def text_embedding(self,input:str,model_name:Optional[str] = None): def text_embedding(self,input:str,model_name:Optional[str] = None):
+3 -3
View File
@@ -200,7 +200,7 @@ class OpenAI_ComputeNode(ComputeNode):
max_token_size = 4000 max_token_size = 4000
result_token = max_token_size result_token = max_token_size
client = AsyncOpenAI() client = AsyncOpenAI(api_key=self.openai_api_key)
try: try:
if llm_inner_functions is None: if llm_inner_functions is None:
logger.info(f"call openai {mode_name} prompts: {prompts}") logger.info(f"call openai {mode_name} prompts: {prompts}")
@@ -215,7 +215,7 @@ class OpenAI_ComputeNode(ComputeNode):
messages=prompts, messages=prompts,
response_format = response_format, response_format = response_format,
functions=llm_inner_functions, functions=llm_inner_functions,
#max_tokens=result_token, max_tokens=result_token,
) # TODO: add temperature to task params? ) # TODO: add temperature to task params?
except Exception as e: except Exception as e:
logger.error(f"openai run LLM_COMPLETION task error: {e}") logger.error(f"openai run LLM_COMPLETION task error: {e}")
@@ -267,8 +267,8 @@ class OpenAI_ComputeNode(ComputeNode):
logger.info(f"openai_node get task: {task.display()}") logger.info(f"openai_node get task: {task.display()}")
result = await self._run_task(task) result = await self._run_task(task)
if result is not None: if result is not None:
task.state = ComputeTaskState.DONE
task.result = result task.result = result
task.state = ComputeTaskState.DONE
asyncio.create_task(_run_task_loop()) asyncio.create_task(_run_task_loop())
@@ -1,6 +0,0 @@
{
"subject": "开发dmc开源客户端",
"from_addr": "sichangjun@buckyos.com",
"to_addr": ["liuzhicong@buckyos.com"],
"date": "2023-4-10 21:00"
}
-51
View File
@@ -1,51 +0,0 @@
最小功能集:4.15准备好oktc合约和客户端工具;4.21之前完成一些矿场节点部署;
Oktc合约和rust接口 (秋总)
实现以DMC结算的bill 和 order done
实现链上挑战—— merkle联通证明;用户提交低深度半路径;矿工提供叶子原文和高深度半路径;(doing)
实现按照价格和质押率索引的spv节点 —— 支持用户按参数匹配下单;(doing)
实现对eth发起的http请求 auth 头认证 —— 支持https实现 链下的 write/restore/challenge 身份认证;(doing
实现oktc client event listener的block number本地持久化;(doing
用户端工具:面向普通存储用户,一键备份和恢复;
源数据管理服务:
注册本地路径,生成链下挑战密码本 ——随机偏移和长度QA(done)
生成链上挑战密码本 —— merkle根和半深度茎节点(doing);
账号服务:
添加本地路径,选择bill id发起orderdone
按参数匹配order ——依赖按参数索引的spv 服务(doing)
生成order提交到交付服务;(done)
交付服务
注册order和关联的源数据(done)
提交merkle根(done
监听链事件,同步order状态,向miner写入源数据;(done)
使用密码本持续发起链下挑战(done
实现链上挑战(doing
恢复数据到本地目录(done
关键日志服务
关键状态改变日志写入(doing
关键状态日志事件监听接口(doing
轻量命令行客户端
服务部署脚本(doing
传入本地文件 和 order参数一键完成备份 (doing)
一键恢复(doing
链下挑战失效时,自动发起链上挑战 ——依赖关键日志服务(doing)
mysql实现移植到sqlite(看时间和问题多不多;undo)
矿场端工具:本版本不是发布重点;保证能在自由的节点上稳定运行即可;结构上保证了一定的伸缩性;
存储扇区管理服务:包括gateway 和 node;保证简单部署和扩展,可靠性暂时不需实现;
扇区gateway服务:注册node,分发扇区读写请求到node;(doing)
扇区node服务:注册本地目录到node,注册为可用扇区;(测试中单node可以直接接入,done)
账号服务:
添加扇区和挂单参数,生成bill(done);
监听链事件,响应新的order转入交付服务;(done)
监听链事件,响应链上挑战转入交付服务;(doing)
交付服务:
注册order和关联的扇区;(done)
对user提供交付相关http接口:
查询miner端order状态(done
写入源数据(done
完成写入后准备生成merkle root准备证明(done
恢复源数据(done
接收链下挑战返回证明(done
自动提交链上挑战(doing
关键日志服务
关键状态改变日志写入(可推迟实现;undo)
自有节点部署
+168 -54
View File
@@ -14,7 +14,16 @@ class IssueUpdateHistory:
def __init__(self, source: str, changes: dict) -> None: def __init__(self, source: str, changes: dict) -> None:
self.source = source self.source = source
self.changes = changes self.changes = changes
def to_json_dict(self) -> dict:
return {
"source": self.source,
"changes": self.changes,
}
@classmethod
def from_json_dict(cls, json_dict: dict) -> "IssueUpdateHistory":
return IssueUpdateHistory(json_dict["source"], json_dict["changes"])
class Issue: class Issue:
def __init__(self) -> None: def __init__(self) -> None:
@@ -26,20 +35,80 @@ class Issue:
self.deadline: datetime = None self.deadline: datetime = None
self.update_history = [] self.update_history = []
self.children = [] self.children = []
self.parent: ObjectID = None self.parent: str = None
def to_json_dict(self) -> dict:
json_dict = {
"id": self.id,
"summary": self.summary,
"state": self.state.name,
"create_time": self.create_time,
"deadline": self.deadline,
"source": self.source,
"parent": self.parent,
}
if self.children is not None and len(self.children) > 0:
json_dict["children"] = []
for child in self.children:
json_dict["children"].append(child.to_json_dict())
if self.update_history is not None and len(self.update_history) > 0:
json_dict["update_history"] = []
for history in self.update_history:
json_dict["update_history"].append(history.to_json_dict())
return json_dict
@classmethod
def from_json_dict(cls, json_dict: dict) -> "Issue":
issue = Issue()
issue.id = json_dict["id"]
issue.summary = json_dict["summary"]
issue.state = IssueState[json_dict["state"]]
issue.create_time = json_dict["create_time"]
issue.deadline = json_dict["deadline"]
issue.source = json_dict["source"]
issue.parent = json_dict["parent"]
if "children" in json_dict:
issue.children = []
for child_json_dict in json_dict["children"]:
child = Issue.from_json_dict(child_json_dict)
issue.children.append(child)
if "update_history" in json_dict:
issue.update_history = []
for history_json_dict in json_dict["update_history"]:
history = IssueUpdateHistory.from_json_dict(history_json_dict)
issue.update_history.append(history)
return issue
@classmethod @classmethod
def object_type(cls) -> ObjectType: def object_type(cls) -> ObjectType:
return ObjectType.from_user_def_type_code(0) return ObjectType.from_user_def_type_code(0)
def to_prompt(self) -> str: def __to_desc(self, desc_list:[], recursion=None):
prompt = { desc = {
"id": self.id, "id": self.id,
"summary": self.summary, "summary": self.summary,
"state": self.state.name, "state": self.state.name,
"deadline": self.deadline "deadline": self.deadline,
} }
return json.dumps(prompt) desc_list.append(desc)
if not recursion or not self.parent:
return
else:
parent = recursion.get_issue_by_id(self.parent)
parent.__to_desc(desc_list, recursion)
def to_prompt(self, recursion=None) -> str:
desc_list = []
self.__to_desc(desc_list, recursion)
root = desc_list.pop()
while len(desc_list) > 0:
child = desc_list.pop()
root["child"] = child
root = child
return json.dumps(root)
@classmethod @classmethod
def prompt_desc(cls) -> str: def prompt_desc(cls) -> str:
@@ -47,7 +116,8 @@ class Issue:
id: a guid string to identify a issue id: a guid string to identify a issue
summary: summary of this issue summary: summary of this issue
state: state of this issue, will be one of [Open, InProgress, Closed], state: state of this issue, will be one of [Open, InProgress, Closed],
deadline: if issue is not closed, deadline is the time to close this issue deadline: if issue is not closed, deadline is the time to close this issue,
children: child issues of this issue
} }
''' '''
@@ -69,14 +139,27 @@ class IssueStorage:
self.path = path self.path = path
if not os.path.exists(path): if not os.path.exists(path):
self.root = root self.root = root
self.__flush()
else: else:
self.root = json.load(open(path, "r")) root_dict = json.load(open(path, "r", encoding="utf-8"))
self.root = Issue.from_json_dict(root_dict)
def __flush(self): def __flush(self):
json.dump(self.root, open(self.path, "w")) json.dump(self.root.to_json_dict(), open(self.path, "w", encoding="utf-8"), ensure_ascii=False, indent=4)
def __get_issue_by_id_in_subtree(self, root_issue: Issue, id: str):
if root_issue.id == id:
return root_issue
if root_issue.children is None or len(root_issue.children) == 0:
return None
for child_issue in root_issue.children:
this_issue = self.__get_issue_by_id_in_subtree(child_issue, id)
if this_issue is not None:
return this_issue
return None
def get_issue_by_id(self, id: str) -> Issue: def get_issue_by_id(self, id: str) -> Issue:
self.root() return self.__get_issue_by_id_in_subtree(self.root, id)
def __get_issue_by_mail_in_subtree(self, root_issue: Issue, mail_id: str): def __get_issue_by_mail_in_subtree(self, root_issue: Issue, mail_id: str):
if root_issue.source == mail_id: if root_issue.source == mail_id:
@@ -102,29 +185,30 @@ class IssueStorage:
this_mail = mail_storage.get_mail_by_id(this_mail.reply_to) this_mail = mail_storage.get_mail_by_id(this_mail.reply_to)
def add_issue(self, source_id: str, issue: dict): def add_issue(self, source_id: str, parent_id: str, summary: str):
parent_id = issue.get("parent") parent_issue = self.get_issue_by_id(parent_id)
parent_issue = self.get_issue(parent_id) issue = Issue()
issue: Issue = issue issue.summary = summary
issue["source"] = source_id issue.source = source_id
issue.parent = parent_id
issue.calculate_id() issue.calculate_id()
parent_issue.children.append(issue) parent_issue.children.append(issue)
self.__flush() self.__flush()
return issue
def update_issue(self, source_id: str, update: dict): def update_issue(self, source_id: str, issue_id: str, update: dict):
issue = self.get_issue(update["id"]) issue = self.get_issue_by_id(issue_id)
source = update["source"]
changes = {} changes = {}
for key, value in update.items(): for key, value in update.items():
if key != "id" and key is not "source": changes[key] = {
changes[key] = { "old": issue[key],
"old": issue[key], "new": value,
"new": value, }
} issue.__dict__[key] = value
issue[key] = value issue.update_history.append(IssueUpdateHistory(source_id, changes))
issue.update_history.append(IssueUpdateHistory(source, changes))
self.__flush() self.__flush()
return issue
class IssueParserEnvironment(Environment): class IssueParserEnvironment(Environment):
@@ -132,29 +216,37 @@ class IssueParserEnvironment(Environment):
super().__init__(env_id) super().__init__(env_id)
self.storage = storage self.storage = storage
update_description = '''update issue with email object''' create_description = '''create a new issue'''
create_param = {
"mail_id": "new issue with which email object id",
"issue_id": '''new issue's parent issue id''',
"summary": '''new issue's summary''',
}
self.add_ai_function(SimpleAIFunction("create_issue",
create_description,
self._create,
create_param))
update_description = '''update an existing issue'''
update_param = { update_param = {
"source_id": "update issue with which email object id", "mail_id": "update issue with which email object id",
"update_content": '''issue fileds to update, json format; "issue_id": '''update issue's id''',
if id field exists, update the issue with the id; "summary": '''issue's new summary''',
if id filed not exists, create a new issue with the content;
other fileds in update_content will be updated to the issue;
''',
} }
self.add_ai_function(SimpleAIFunction("update_issue", self.add_ai_function(SimpleAIFunction("update_issue",
update_description, update_description,
self._update, self._update,
update_param)) update_param))
async def _update(self, source_id: str, update_content: str): async def _create(self, mail_id: str, issue_id: str, summary: str):
update_issue = json.loads(update_content) issue = self.storage.add_issue(mail_id, issue_id, summary)
issue_id = update_issue.get("id") return issue.id
if issue_id:
self.storage.update_issue(source_id, update_issue) async def _update(self, mail_id: str, issue_id: str, summary: str):
else: update = {}
self.storage.add_issue(source_id, update_issue) update["summary"] = summary
issue = self.storage.update_issue(mail_id, issue_id, update)
return issue.id
class IssueParser: class IssueParser:
@@ -169,10 +261,30 @@ class IssueParser:
root_issue = None root_issue = None
if "root_issue" in config: if "root_issue" in config:
root_issue = Issue() root_config = config["root_issue"]
root_issue.summary = config["root_issue"] root_issue = IssueParser.__load_issue_config(root_config)
IssueParser.__calac_issue_id(root_issue)
self.issue_storage = IssueStorage(issue_path, root_issue) self.issue_storage = IssueStorage(issue_path, root_issue)
self.llm_env = IssueParserEnvironment("issue_parser", self.issue_storage) self.llm_env = IssueParserEnvironment("issue_parser", self.issue_storage)
@classmethod
def __load_issue_config(cls, issue_config: dict) -> Issue:
issue = Issue()
issue.summary = issue_config["summary"]
if "children" in issue_config:
for child_config in issue_config["children"]:
child_issue = cls.__load_issue_config(child_config)
issue.children.append(child_issue)
return issue
@classmethod
def __calac_issue_id(cls, issue: Issue):
issue_id = issue.calculate_id()
for child in issue.children:
child.parent = issue_id
cls.__calac_issue_id(child)
def get_path(self) -> str: def get_path(self) -> str:
return self.config["path"] return self.config["path"]
@@ -182,19 +294,21 @@ class IssueParser:
mail = self.mail_storage.get_mail_by_id(mail_id) mail = self.mail_storage.get_mail_by_id(mail_id)
issue = self.issue_storage.get_issue_by_mail(self.mail_storage, mail) issue = self.issue_storage.get_issue_by_mail(self.mail_storage, mail)
mail_str = mail.to_prompt() mail_str = mail.to_prompt()
issue_str = issue.to_prompt() issue_str = issue.to_prompt(recursion=self.issue_storage)
mail_desc = Mail.prompt_desc() mail_desc = Mail.prompt_desc()
issue_desc = Issue.prompt_desc() issue_desc = Issue.prompt_desc()
prompt = f'''I'll give a mail in json format, {mail_desc}; prompt = AgentPrompt()
and a issue in json format, {issue_desc}; prompt.system_message = {"role": "system", "content": f'''
you should read this mail {mail_str}, see if this mail associated with this issue {issue_str}; I'm a CEO of a company named 巴克云; You'ar my assistant, and you should help me to manage my issues. Issues is a concept in software development of this company, but I use it to manage my work.
if this mail is about a new child issue of this issue, create a new issue with this mail, fill param update_content's summary field will mail content, set parent field with id of this issue; I'll give you a mail in json format, {mail_desc};
if this mail will update this issue, set id filed to this issue, fill update_content param with new summary and new state with this mail content; and a issue in json format, {issue_desc}. Read mail's fileds and issue's fileds, and decide if you should update the issue or create a new issue with this mail.
then you should call update_issue function with source_id set to this mail id, and update_content in json format; Then call the function create_issue or update_issue.
if this mail is not associated with issue, you should ignore this mail without an function call; if this mail is not associated with issue, you should ignore this mail.'''}
'''
prompt.append(AgentPrompt(f'''Mail is {mail_str}, issue is {issue_str}. Answer me the function's return value or None if igonred.
'''))
llm_result = await BaseAIAgent.do_llm_complection(self.llm_env, AgentPrompt(prompt), AgentMsg(), "gpt-4", 16000) llm_result = await BaseAIAgent.do_llm_complection(prompt, "gpt-4-1106-preview", 4000, env=self.llm_env)
return "update issue" return "update issue"
+4 -1
View File
@@ -31,4 +31,7 @@ class LocalEmail:
else: else:
yield (mail_id, str(mail_id)) yield (mail_id, str(mail_id))
class LocalEmailWithFilter:
def __init__(self, env: KnowledgePipelineEnvironment, config:dict):
pass
-1
View File
@@ -261,5 +261,4 @@ class MailStorage:
(uid, mail.id, mail.date, mail.from_addr), (uid, mail.id, mail.date, mail.from_addr),
) )
+1 -1
View File
@@ -22,7 +22,7 @@ class ObjectType(IntEnum):
return (self.value - 200) if self.is_user_def() else None return (self.value - 200) if self.is_user_def() else None
@classmethod @classmethod
def from_user_def_type_code(value): def from_user_def_type_code(cls, value):
return value + 200 return value + 200
+3 -1
View File
@@ -23,7 +23,9 @@ from prompt_toolkit.styles import Style
directory = os.path.dirname(__file__) directory = os.path.dirname(__file__)
sys.path.append(directory + '/../../') sys.path.append(directory + '/../../')
# import os
# os.environ['HTTP_PROXY'] = '127.0.0.1:10809'
# os.environ['HTTPS_PROXY'] = '127.0.0.1:10809'
import proxy import proxy
from aios_kernel import * from aios_kernel import *