From 857a7ed956bf7a093e01cc7723ed37b87a2c20c1 Mon Sep 17 00:00:00 2001 From: Liu Zhicong Date: Tue, 26 Sep 2023 18:46:26 -0700 Subject: [PATCH] fix bugs~ --- rootfs/agents/Jarvis/agent.toml | 10 +- src/aios_kernel/__init__.py | 6 +- src/aios_kernel/agent_message.py | 1 + src/aios_kernel/bus.py | 2 +- src/aios_kernel/compute_kernel.py | 77 ++++--------- src/aios_kernel/compute_task.py | 6 + src/aios_kernel/storage.py | 6 +- src/aios_kernel/tg_tunnel.py | 20 +++- src/requirements.txt | 164 +++++++++++++-------------- src/service/aios_shell/aios_shell.py | 69 ++++++----- 10 files changed, 183 insertions(+), 178 deletions(-) diff --git a/rootfs/agents/Jarvis/agent.toml b/rootfs/agents/Jarvis/agent.toml index c8c3ae7..c27f3bb 100644 --- a/rootfs/agents/Jarvis/agent.toml +++ b/rootfs/agents/Jarvis/agent.toml @@ -2,7 +2,6 @@ instance_id = "Jarvis" fullname = "Jarvis" llm_model_name = "gpt-3.5-turbo-16k-0613" max_token_size = 16000 -#enable_function =["add_event"] #enable_kb = "true" enable_timestamp = "true" owner_prompt = "我是你的主人{name}" @@ -26,7 +25,10 @@ David,私人画家 消息内容 ``` 2.你可以访问我的Calender,查看我的日程安排。如果你在处理信息的过程中需要修改我的日程安排,请直接用合适的方法修改。 -3.你可以访问我的个人信息库,当你处理我的信息时,如果需要用到我的个人信息,请先用合适的方法进行查询,然后再基于查询的结果进行进一步处理后再将结果发给我。 -4.你能根据我的需要对系统进行配置,但在修改任何配置前,请先和我确认。 -5.不符合上述规则的信息,请尽力处理。 +3.不符合上述规则的信息,请尽力处理。 """ + + +#3.你可以访问我的个人信息库,当你处理我的信息时,如果需要用到我的个人信息,请先用合适的方法进行查询,然后再基于查询的结果进行进一步处理后再将结果发给我。 +#4.你能根据我的需要对系统进行配置,但在修改任何配置前,请先和我确认。 + diff --git a/src/aios_kernel/__init__.py b/src/aios_kernel/__init__.py index 637ee7d..36ef512 100644 --- a/src/aios_kernel/__init__.py +++ b/src/aios_kernel/__init__.py @@ -1,8 +1,8 @@ from .environment import Environment,EnvironmentEvent -from .agent_message import AgentMsg,AgentMsgStatus +from .agent_message import AgentMsg,AgentMsgStatus,AgentMsgType from .chatsession import AIChatSession from .agent import AIAgent,AIAgentTemplete,AgentPrompt -from .compute_kernel import ComputeKernel,ComputeTask +from .compute_kernel import ComputeKernel,ComputeTask,ComputeTaskResult,ComputeTaskState,ComputeTaskType from .compute_node import ComputeNode,LocalComputeNode from .open_ai_node import OpenAI_ComputeNode from .knowledge_base import KnowledgeBase @@ -24,5 +24,5 @@ from .workspace_env import WorkspaceEnvironment from .local_stability_node import Local_Stability_ComputeNode from .stability_node import Stability_ComputeNode -AIOS_Version = "0.5.1, build 2023-9-17" +AIOS_Version = "0.5.1, build 2023-9-26" diff --git a/src/aios_kernel/agent_message.py b/src/aios_kernel/agent_message.py index 49daf3a..1fcaf44 100644 --- a/src/aios_kernel/agent_message.py +++ b/src/aios_kernel/agent_message.py @@ -11,6 +11,7 @@ class AgentMsgType(Enum): TYPE_INTERNAL_CALL = 1 TYPE_ACTION = 2 TYPE_EVENT = 3 + TYPE_SYSTEM = 4 class AgentMsgStatus(Enum): RESPONSED = 0 diff --git a/src/aios_kernel/bus.py b/src/aios_kernel/bus.py index 16ede81..8d38e53 100644 --- a/src/aios_kernel/bus.py +++ b/src/aios_kernel/bus.py @@ -78,7 +78,7 @@ class AIBus: retry_times = 0 while True: - resp = sender_handler.results.get(msg.msg_id) + resp : AgentMsg = sender_handler.results.get(msg.msg_id) if resp is not None: msg.resp_msg = resp msg.status = AgentMsgStatus.RESPONSED diff --git a/src/aios_kernel/compute_kernel.py b/src/aios_kernel/compute_kernel.py index 661110b..0caab10 100644 --- a/src/aios_kernel/compute_kernel.py +++ b/src/aios_kernel/compute_kernel.py @@ -7,7 +7,7 @@ from asyncio import Queue from .agent import AgentPrompt from .compute_node import ComputeNode -from .compute_task import ComputeTask, ComputeTaskState, ComputeTaskResult, ComputeTaskType +from .compute_task import ComputeTask, ComputeTaskState, ComputeTaskResult, ComputeTaskType,ComputeTaskResultCode logger = logging.getLogger(__name__) @@ -105,10 +105,8 @@ class ComputeKernel: task_req.set_llm_params(prompt, mode_name, max_token,inner_functions) self.run(task_req) return task_req - - async def do_llm_completion(self, prompt: AgentPrompt, mode_name: Optional[str] = None, max_token: int = 0, inner_functions = None) -> str: - task_req = self.llm_completion(prompt, mode_name, max_token,inner_functions) - + + async def _send_task(self,task_req:ComputeTask)->ComputeTaskResult: async def check_timer(): check_times = 0 while True: @@ -126,10 +124,18 @@ class ComputeKernel: check_times += 1 await asyncio.create_task(check_timer()) - if task_req.state == ComputeTaskState.DONE: + if task_req.result: return task_req.result + else: + time_out_result = ComputeTaskResult() + time_out_result.result_code = ComputeTaskResultCode.TIMEOUT + time_out_result.set_from_task(task_req) + ## craete timeout task_result + + async def do_llm_completion(self, prompt: AgentPrompt, mode_name: Optional[str] = None, max_token: int = 0, inner_functions = None) -> str: + task_req = self.llm_completion(prompt, mode_name, max_token,inner_functions) + return await self._send_task(task_req) - raise Exception("error!") def text_embedding(self,input:str,model_name:Optional[str] = None): @@ -140,25 +146,10 @@ class ComputeKernel: async def do_text_embedding(self,input:str,model_name:Optional[str] = None) -> [float]: task_req = self.text_embedding(input,model_name) - async def check_timer(): - check_times = 0 - while True: - if task_req.state == ComputeTaskState.DONE: - break + task_result = await self._send_task(task_req) - if task_req.state == ComputeTaskState.ERROR: - break - - if check_times >= 20: - task_req.state = ComputeTaskState.ERROR - break - - await asyncio.sleep(0.5) - check_times += 1 - - await asyncio.create_task(check_timer()) if task_req.state == ComputeTaskState.DONE: - return task_req.result.result + return task_result.result return "error!" @@ -179,22 +170,10 @@ class ComputeKernel: task_req.task_type = ComputeTaskType.TEXT_2_VOICE self.run(task_req) - check_times = 0 - while True: - if task_req.state == ComputeTaskState.DONE: - break - if task_req.state == ComputeTaskState.ERROR: - break - if check_times >= 60: - task_req.state = ComputeTaskState.ERROR - break - await asyncio.sleep(0.5) - check_times += 1 + task_result = await self._send_task(task_req) if task_req.state == ComputeTaskState.DONE: - return task_req.result.result - else: - raise Exception("do_text_to_speech failed!") + return task_result.result def text_2_image(self, prompt:str, model_name:Optional[str] = None): @@ -205,27 +184,9 @@ class ComputeKernel: async def do_text_2_image(self, prompt:str, model_name:Optional[str] = None) -> [str, ComputeTaskResult]: task_req = self.text_2_image(prompt,model_name) - async def check_timer(): - check_times = 0 - while True: - if task_req.state == ComputeTaskState.DONE: - break - - if task_req.state == ComputeTaskState.ERROR: - break - - #may be it will take a long time to generate a image - if check_times >= 60: - task_req.state = ComputeTaskState.ERROR - break - - await asyncio.sleep(0.5) - check_times += 1 - - await asyncio.create_task(check_timer()) - + task_result = self._send_task(task_req) if task_req.state == ComputeTaskState.DONE: - return None, task_req.result + return None, task_result return task_req.error_str, None diff --git a/src/aios_kernel/compute_task.py b/src/aios_kernel/compute_task.py index 56a8387..dfc58ad 100644 --- a/src/aios_kernel/compute_task.py +++ b/src/aios_kernel/compute_task.py @@ -3,6 +3,11 @@ from enum import Enum import uuid import time +class ComputeTaskResultCode(Enum): + OK = 0 + TIMEOUT = 1 + NO_WORK = 2 + class ComputeTaskState(Enum): DONE = 0 @@ -95,3 +100,4 @@ class ComputeTaskResult: def set_from_task(self, task: ComputeTask): self.task_id = task.task_id self.callchain_id = task.callchain_id + task.result = self diff --git a/src/aios_kernel/storage.py b/src/aios_kernel/storage.py index b0d34c3..2d83af6 100644 --- a/src/aios_kernel/storage.py +++ b/src/aios_kernel/storage.py @@ -92,14 +92,16 @@ class UserConfig: def get_config_item(self,key:str) -> Any: config_item = self.config_table.get(key) if config_item is None: - raise Exception("user config key %s not exist",key) + logger.warning(f"user config key {key} not exist") + return None return config_item def get_value(self,key:str)->Any: config_item = self.config_table.get(key) if config_item is None: - raise Exception("user config key %s not exist",key) + logger.warning(f"user config key {key} not exist") + return None if config_item.value is None: return config_item.default_value diff --git a/src/aios_kernel/tg_tunnel.py b/src/aios_kernel/tg_tunnel.py index 7062a99..442deeb 100644 --- a/src/aios_kernel/tg_tunnel.py +++ b/src/aios_kernel/tg_tunnel.py @@ -32,10 +32,13 @@ class TelegramTunnel(AgentTunnel): async def load_from_config(self,config:dict)->bool: + self.type = "TelegramTunnel" self.tg_token = config["token"] self.target_id = config["target"] self.tunnel_id = config["tunnel_id"] - self.type = "TelegramTunnel" + if config.get("allow") is not None: + self.allow_group = config["allow"] + return True def dump_to_config(self) -> dict: @@ -47,6 +50,7 @@ class TelegramTunnel(AgentTunnel): self.tg_token = tg_token self.bot:Bot = None self.update_queue = None + self.allow_group = "contact" async def _do_process_raw_message(self,bot: Bot, update_id: int) -> int: # Request updates after the last update_id @@ -88,6 +92,11 @@ class TelegramTunnel(AgentTunnel): except Forbidden: # The user has removed or blocked the bot. update_id += 1 + except Exception as e: + logger.error(f"tg_tunnel error:{e}") + await asyncio.sleep(1) + + asyncio.create_task(_run_app()) logger.info(f"tunnel {self.tunnel_id} started.") @@ -130,7 +139,16 @@ class TelegramTunnel(AgentTunnel): if contact is not None: reomte_user_name = contact.name + if not contact.is_family_member: + if self.allow_group != "contact" and self.allow_group !="guest": + await update.message.reply_text(f"You are not allowed to talk to me! Please contact my father~") + return + else: + if self.allow_group != "guest": + await update.message.reply_text(f"You are not allowed to talk to me! Please contact my father~") + return + if cm.is_auto_create_contact_from_telegram: contact_name = update.effective_user.first_name if update.effective_user.last_name is not None: diff --git a/src/requirements.txt b/src/requirements.txt index e96eb07..7bd02d6 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,89 +1,89 @@ -aiofiles==23.2.1 -aiohttp==3.8.5 -aioimaplib==1.0.1 -aiosignal==1.3.1 -aiosmtplib==2.0.2 -anyio==4.0.0 -async-timeout==4.0.3 -attrs==23.1.0 -backoff==2.2.1 -base36==0.1.1 -base58==2.1.1 -beautifulsoup4==4.12.2 -cachetools==5.3.1 -certifi==2023.7.22 -charset-normalizer==3.2.0 -chroma-hnswlib==0.7.1 -chromadb==0.4.0 -click==8.1.7 -colorama==0.4.6 -coloredlogs==15.0.1 -decorator==4.4.2 -fastapi==0.99.1 -filelock==3.12.3 -flatbuffers==23.5.26 -frozenlist==1.4.0 -fsspec==2023.9.0 -google==3.0.0 -google-api-core==2.11.1 -google-auth==2.23.0 -google-cloud==0.34.0 -google-cloud-texttospeech==2.14.1 -googleapis-common-protos==1.60.0 +aiofiles>=23.2.1 +aiohttp>=3.8.5 +aioimaplib>=1.0.1 +aiosignal>=1.3.1 +aiosmtplib>=2.0.2 +anyio>=4.0.0 +async-timeout>=4.0.3 +attrs>=23.1.0 +backoff>=2.2.1 +base36>=0.1.1 +base58>=2.1.1 +beautifulsoup4>=4.12.2 +cachetools>=5.3.1 +certifi>=2023.7.22 +charset-normalizer>=3.2.0 +chroma-hnswlib>=0.7.1 +chromadb>=0.4.0 +click>=8.1.7 +colorama>=0.4.6 +coloredlogs>=15.0.1 +decorator>=4.4.2 +fastapi>=0.99.1 +filelock>=3.12.3 +flatbuffers>=23.5.26 +frozenlist>=1.4.0 +fsspec>=2023.9.0 +google>=3.0.0 +google-api-core>=2.11.1 +google-auth>=2.23.0 +google-cloud>=0.34.0 +google-cloud-texttospeech>=2.14.1 +googleapis-common-protos>=1.60.0 +h11>=0.14.0 +httpcore>=0.17.3 +httptools>=0.6.0 +httpx>=0.24.1 +huggingface-hub>=0.16.4 +humanfriendly>=10.0 +idna>=3.4 +imageio>=2.31.3 +imageio-ffmpeg>=0.4.8 +importlib-resources>=6.0.1 +mail-parser>=3.15.0 +monotonic>=1.6 +moviepy>=1.0.0 +mpmath>=1.3.0 +multidict>=6.0.4 +numpy>=1.25.2 +onnxruntime>=1.15.1 +openai>=0.28.0 +overrides>=7.4.0 +packaging>=23.1 +pandas>=2.1.0 +Pillow>=10.0.0 +posthog>=3.0.2 +proglog>=0.1.10 +prompt-toolkit>=3.0.39 +proto-plus>=1.22.3 +pulsar-client>=3.3.0 +pyasn1>=0.5.0 +pyasn1-modules>=0.3.0 +pydantic>=1.10.12 +PyPika>=0.48.9 +pyreadline3>=3.4.1 +python-dateutil>=2.8.2 +python-dotenv>=1.0.0 +python-telegram-bot>=20.5 +pytz>=2023.3.post1 +PyYAML>=6.0.1 +requests>=2.31.0 +rsa>=4.9 +simplejson>=3.19.1 +six>=1.16.0 +sniffio>=1.3.0 +soupsieve>=2.5 +starlette>=0.27.0 +sympy>=1.12 +tokenizers>=0.14.0 +toml>=0.10.0 +protobuf grpcio grpcio-status -h11==0.14.0 -httpcore==0.17.3 -httptools==0.6.0 -httpx==0.24.1 -huggingface-hub==0.16.4 -humanfriendly==10.0 -idna==3.4 -imageio==2.31.3 -imageio-ffmpeg==0.4.8 -importlib-resources==6.0.1 -mail-parser==3.15.0 -monotonic==1.6 -moviepy==1.0.0 -mpmath==1.3.0 -multidict==6.0.4 -numpy==1.25.2 -onnxruntime==1.15.1 -openai==0.28.0 -overrides==7.4.0 -packaging==23.1 -pandas==2.1.0 -Pillow==10.0.0 -posthog==3.0.2 -proglog==0.1.10 -prompt-toolkit==3.0.39 -proto-plus==1.22.3 -protobuf -pulsar-client==3.3.0 -pyasn1==0.5.0 -pyasn1-modules==0.3.0 -pydantic==1.10.12 -PyPika==0.48.9 -pyreadline3==3.4.1 -python-dateutil==2.8.2 -python-dotenv==1.0.0 -python-telegram-bot==20.5 -pytz==2023.3.post1 -PyYAML==6.0.1 -requests==2.31.0 -rsa==4.9 -simplejson==3.19.1 -six==1.16.0 -sniffio==1.3.0 -soupsieve==2.5 -starlette==0.27.0 -sympy==1.12 -telegram==0.0.1 -tokenizers==0.14.0 -toml==0.10.0 pysocks chardet pydub aiosqlite python-telegram-bot -pydub \ No newline at end of file +pydub +stability_sdk \ No newline at end of file diff --git a/src/service/aios_shell/aios_shell.py b/src/service/aios_shell/aios_shell.py index c525b47..da5e7ee 100644 --- a/src/service/aios_shell/aios_shell.py +++ b/src/service/aios_shell/aios_shell.py @@ -24,7 +24,7 @@ directory = os.path.dirname(__file__) sys.path.append(directory + '/../../') -from aios_kernel import AIOS_Version,UserConfigItem,AIStorage,Workflow,AIAgent,AgentMsg,AgentMsgStatus,ComputeKernel,OpenAI_ComputeNode,AIBus,AIChatSession,AgentTunnel,TelegramTunnel,CalenderEnvironment,Environment,EmailTunnel,LocalLlama_ComputeNode,Local_Stability_ComputeNode,Stability_ComputeNode,PaintEnvironment +from aios_kernel import AIOS_Version,AgentMsgType,UserConfigItem,AIStorage,Workflow,AIAgent,AgentMsg,AgentMsgStatus,ComputeKernel,OpenAI_ComputeNode,AIBus,AIChatSession,AgentTunnel,TelegramTunnel,CalenderEnvironment,Environment,EmailTunnel,LocalLlama_ComputeNode,Local_Stability_ComputeNode,Stability_ComputeNode,PaintEnvironment from aios_kernel import ContactManager,Contact import proxy from aios_kernel import * @@ -199,9 +199,12 @@ class AIOS_Shell: agent_msg.topic = topic resp = await AIBus.get_default_bus().send_message(agent_msg) if resp is not None: - return resp.body + if resp.msg_type != AgentMsgType.TYPE_SYSTEM: + return resp.body + else: + return f"Process Message Error: {resp.body} Please check logs/aios.log for more details!" else: - return "error!" + return "System Error: Timeout, no resopnse! Please check logs/aios.log for more details!" async def _user_process_msg(self,msg:AgentMsg) -> AgentMsg: pass @@ -211,12 +214,13 @@ class AIOS_Shell: tunnel_config = {} tunnel_config["tunnel_id"] = f"{tunnel_type}_2_{tunnel_target}" tunnel_config["target"] = tunnel_target - intpu_table = {} + input_table = {} tunnel_introduce : str = "" match tunnel_type: case "telegram": tunnel_config["type"] = "TelegramTunnel" - intpu_table["token"] = UserConfigItem("telegram bot token") + input_table["token"] = UserConfigItem("telegram bot token") + input_table["allow"] = UserConfigItem("allow group (default is member,you can choose contact or guest)") case "email": tunnel_config["type"] = "EmailTunnel" case _: @@ -226,7 +230,7 @@ class AIOS_Shell: intro_text = FormattedText([("class:prompt", tunnel_introduce)]) print_formatted_text(intro_text,style=shell_style) - for key,item in intpu_table.items(): + for key,item in input_table.items(): user_input = await try_get_input(f"{key} : {item.desc}") if user_input is None: return None @@ -246,7 +250,7 @@ class AIOS_Shell: if f: toml.dump(all_tunnels,f) except Exception as e: - logger.warning(f"load tunnels config from {tunnels_config_path} failed!") + logger.warning(f"load tunnels config from {tunnels_config_path} failed! {e}") async def handle_contact_commands(self,args): cm = ContactManager.get_instance() @@ -353,15 +357,17 @@ class AIOS_Shell: async def call_func(self,func_name, args): match func_name: case 'send': - target_id = args[0] - msg_content = args[1] - topic = args[2] - resp = await self.send_msg(msg_content,target_id,topic,self.username) - show_text = FormattedText([("class:title", f"{self.current_topic}@{self.current_target} >>> "), - ("class:content", resp)]) + show_text = FormattedText([("class:error", f'send args error,/send Tracy "Hello! It is a good day!" default')]) + if len(args) == 3: + target_id = args[0] + msg_content = args[1] + topic = args[2] + resp = await self.send_msg(msg_content,target_id,topic,self.username) + show_text = FormattedText([("class:title", f"{self.current_topic}@{self.current_target} >>> "), + ("class:content", resp)]) return show_text case 'set_config': - show_text = FormattedText([("class:title", f"set config failed!")]) + show_text = FormattedText([("class:error", f"set config args error,/set_config $config_item! ")]) if len(args) == 1: key = args[0] config_item = AIStorage.get_instance().get_user_config().get_config_item(key) @@ -372,10 +378,12 @@ class AIOS_Shell: AIStorage.get_instance().get_user_config().set_value(key,value) await AIStorage.get_instance().get_user_config().save_to_user_config() show_text = FormattedText([("class:title", f"set {key} to {value} success!")]) + else: + show_text = FormattedText([("class:error", f"set config failed! config item {key} not found!")]) return show_text case 'connect': - show_text = FormattedText([("class:title", "args error, /connect $target telegram | email")]) + show_text = FormattedText([("class:error", "args error, /connect $target")]) if len(args) < 1: return show_text tunnel_target = args[0] @@ -442,12 +450,12 @@ class AIOS_Shell: AIStorage.get_instance().disable_feature(feature) show_text = FormattedText([("class:title", f"Feature {feature} disabled!")]) return show_text - case 'login': - if len(args) >= 1: - self.username = args[0] - AIBus().get_default_bus().register_message_handler(self.username,self._user_process_msg) + #case 'login': + # if len(args) >= 1: + # self.username = args[0] + # AIBus().get_default_bus().register_message_handler(self.username,self._user_process_msg) - return self.username + " login success!" + # return self.username + " login success!" case 'history': num = 10 offset = 0 @@ -491,12 +499,14 @@ def parse_function_call(func_string): else: return None -async def try_get_input(desc:str,check_func:callable = None) -> str: +async def try_get_input(desc:str,mutil_line:bool = False,check_func:callable = None) -> str: user_input = await session.prompt_async(f"{desc} \nType /exit to abort. \nPlease input:",style=shell_style) err_str = "" if check_func is None: if len(user_input) > 0: if user_input != "/exit": + if mutil_line is False: + user_input = user_input.strip() return user_input else: return None @@ -580,7 +590,10 @@ async def main(): level=logging.INFO, format='[%(asctime)s]%(name)s[%(levelname)s]: %(message)s') else: - log_file = f"{AIStorage.get_instance().get_myai_dir()}/logs/aios_shell.log" + dir_path = f"{AIStorage.get_instance().get_myai_dir()}/logs" + if not os.path.exists(dir_path): + os.makedirs(dir_path) + log_file = f"{AIStorage.get_instance().get_myai_dir()}/logs/aios.log" handler = RotatingFileHandler(log_file, maxBytes=50*1024*1024, backupCount=100) logging.basicConfig(handlers=[handler], @@ -591,6 +604,8 @@ async def main(): if os.name != 'nt': if os.getppid() == 1: is_daemon = True + if not sys.stdout.isatty(): + is_daemon = True shell = AIOS_Shell("user") shell.declare_all_user_config() @@ -604,8 +619,10 @@ async def main(): #Remind users to enter necessary configurations. if await get_user_config_from_input(check_result) is False: return 1 - + shell.username = AIStorage.get_instance().get_user_config().get_value("username") init_result = await shell.initial() + proxy.apply_storage() + if init_result is False: if is_daemon: logger.error("aios shell initial failed!") @@ -614,16 +631,14 @@ async def main(): print("aios shell initial failed!") return 1 - print(f"aios shell {shell.get_version()} ready.") + print(f"aios shell {shell.get_version()} ready. Daemon:{is_daemon}") + logger.info(f"aios shell {shell.get_version()} ready. Daemon:{is_daemon}") if is_daemon: return await main_daemon_loop(shell) - proxy.apply_storage() - completer = WordCompleter(['/send $target $msg $topic', '/open $target $topic', '/history $num $offset', - '/login $username', '/connect $target', '/contact $name', '/knowledge add email | dir',