diff --git a/doc/promps/Review Task.md b/doc/promps/Review Task.md index dc661ed..28056d6 100644 --- a/doc/promps/Review Task.md +++ b/doc/promps/Review Task.md @@ -120,3 +120,4 @@ The result of my planned execution must be directly parsed by `python json.loads ## RetryTask 对未成功的任务进行再次处理 +注意RetryTask和RetryTodo的区别 diff --git a/doc/promps/self-learn.md b/doc/promps/self-learn.md index e69de29..5007259 100644 --- a/doc/promps/self-learn.md +++ b/doc/promps/self-learn.md @@ -0,0 +1,2 @@ +self learn通常是根据既定目标,对KB进行学习,或则主动扩展KB的行为。 +self learn的结果是可以被组织(workflow)共享 \ No newline at end of file diff --git a/rootfs/agents/Jarvis/agent.toml b/rootfs/agents/Jarvis/agent.toml index 208d49f..bfb6cc4 100644 --- a/rootfs/agents/Jarvis/agent.toml +++ b/rootfs/agents/Jarvis/agent.toml @@ -11,16 +11,17 @@ owner_prompt = "I am your master{name}" contact_prompt = "I am your master's friend{name}" role_desc = """ -Your name is Jarvis, the super personal assistant to the master. +Your name is Jarvis, the super personal assistant to the master, The focus of work is the support of the schedule management and schedule affairs. """ [behavior.on_message] type="LLMAgentMessageProcess" + process_description=""" 1. Based on your role, combined with existing information, make a brief and efficient reply. 2. Be mindful of the identity of the person you are chatting with and provide services accordingly based on their status. 3. Understand the intention of the dialogue, while using the necessary reply, use the appropriate, supported ACTION. -4. If you feel that there is a potential Task in the dialogue, you can create these tasks through appropriate ACTION. Be careful to query whether there are the same task before creating.Using the query interface is a high -cost behavior. +4. If you feel that there is a potential Task in the dialogue, you can create these tasks through appropriate ACTION. Be careful to query whether there are the same task before creating. Using the query interface is a high-cost behavior. 5. You are proficient in the languages of various countries and try to communicate with each other's mother tongue. """ @@ -44,6 +45,8 @@ known_info_tips = """ tools_tips = """ """ +llm_context.actions.enable = ["agent.workspace.create_task"] +llm_context.functions.enable = ["agent.workspace.list_task"] [behavior.review_task] type="ReviewTaskProcess" @@ -82,11 +85,7 @@ known_info_tips = """ tools_tips = """ """ -[llm_context.actions] -enable = ["agent.memory.append_chatlog"] -[llm_context.functions] -enable = [] [behavior.do] # do TODO type="DoTodoProcess" diff --git a/src/aios/__init__.py b/src/aios/__init__.py index 82c27a1..cba723e 100644 --- a/src/aios/__init__.py +++ b/src/aios/__init__.py @@ -10,6 +10,7 @@ from .agent.agent import AIAgent,AIAgentTemplete, BaseAIAgent from .agent.role import AIRole,AIRoleGroup from .agent.workflow import Workflow from .agent.agent_memory import AgentMemory +from .agent.workspace import AgentWorkspace from .agent.llm_context import LLMProcessContext,GlobaToolsLibrary,SimpleLLMContext from .frame.compute_kernel import ComputeKernel,ComputeTask,ComputeTaskResult,ComputeTaskState,ComputeTaskType diff --git a/src/aios/agent/llm_context.py b/src/aios/agent/llm_context.py index b3e2fb6..a3fd16c 100644 --- a/src/aios/agent/llm_context.py +++ b/src/aios/agent/llm_context.py @@ -17,11 +17,11 @@ class LLMProcessContext: def function2action(ai_func:AIFunction) -> AIAction: async def exec_func(params:Dict) -> str: return await ai_func.execute(params) - return SimpleAIAction(ai_func.get_name(),ai_func.get_detail_description(),exec_func) + return SimpleAIAction(ai_func.get_id(),ai_func.get_detail_description(),exec_func) @staticmethod - def aifunction_to_inner_function(self,all_inner_function:List[AIFunction]) -> List[Dict]: + def aifunctions_to_inner_functions(all_inner_function:List[AIFunction]) -> List[Dict]: result_func = [] result_len = 0 for inner_func in all_inner_function: @@ -34,6 +34,7 @@ class LLMProcessContext: result_func.append(this_func) return result_func + @abstractmethod def get_ai_function(self,func_name:str) -> AIFunction: pass @@ -63,13 +64,14 @@ class LLMProcessContext: def get_value(self,key:str) -> Optional[str]: pass - def list_actions(self,path:str) -> List[AIAction]: - return "No more actions!" + #def list_actions(self,path:str) -> List[AIAction]: + # return "No more actions!" - def list_functions(self,path:str) -> List[AIFunction]: - return "No more tool functions!" + #def list_functions(self,path:str) -> List[AIFunction]: + # return "No more tool functions!" class GlobaToolsLibrary: + _instance = None @classmethod def get_instance(cls) -> 'GlobaToolsLibrary': if cls._instance is None: @@ -89,10 +91,10 @@ class GlobaToolsLibrary: return self.all_preset_context.get(preset_id) def register_tool_function(self,function:AIFunction) -> None: - if self.all_tool_functions.get(function.get_name()): - logger.warning(f"Tool function {function.get_name()} already exists! will be replaced!") + if self.all_tool_functions.get(function.get_id()): + logger.warning(f"Tool function {function.get_id()} already exists! will be replaced!") - self.all_tool_functions[function.get_name()] = function + self.all_tool_functions[function.get_id()] = function def get_tool_function(self,function_name:str) -> AIFunction: return self.all_tool_functions.get(function_name) @@ -139,18 +141,19 @@ class SimpleLLMContext(LLMProcessContext): return None disable_actions = config.get("disable") - for disable_action in disable_actions: - if result.get(disable_action): - result.pop(disable_action) - else: - func_set = GlobaToolsLibrary.get_instance().get_function_set(action_id) - if func_set: - for _func_id in func_set: - if result.get(_func_id): - result.pop(_func_id) + if disable_actions: + for disable_action in disable_actions: + if result.get(disable_action): + result.pop(disable_action) else: - logger.error(f"load_action_set_from_config failed! disable action id {action_id} not found!") - return None + func_set = GlobaToolsLibrary.get_instance().get_function_set(action_id) + if func_set: + for _func_id in func_set: + if result.get(_func_id): + result.pop(_func_id) + else: + logger.error(f"load_action_set_from_config failed! disable action id {action_id} not found!") + return None return result @@ -182,18 +185,19 @@ class SimpleLLMContext(LLMProcessContext): disable_functions = config.get("disable") - for disable_function in disable_functions: - if result.get(disable_function): - result.pop(disable_function) - else: - func_set = GlobaToolsLibrary.get_instance().get_function_set(func_id) - if func_set: - for func_id in func_set: - if result.get(func_id): - result.pop(func_id) + if disable_functions: + for disable_function in disable_functions: + if result.get(disable_function): + result.pop(disable_function) else: - logger.error(f"load_function_set_from_config failed! disable function id {disable_function} not found!") - return None + func_set = GlobaToolsLibrary.get_instance().get_function_set(func_id) + if func_set: + for func_id in func_set: + if result.get(func_id): + result.pop(func_id) + else: + logger.error(f"load_function_set_from_config failed! disable function id {disable_function} not found!") + return None return result @@ -268,15 +272,14 @@ class SimpleLLMContext(LLMProcessContext): def set_value(self,key:str,value:str): self.values[key] = value - #def get_ai_function(self,func_name:str) -> AIFunction: - # func = self.functions.get(func_name) - # if func is not None: - # return func - - # for set_name in self.func_sets.keys(): - # func = self.func_sets[set_name].get(func_name) - # if func is not None: - # return func + def get_ai_function(self,func_name:str) -> AIFunction: + for func in self.functions.values(): + if func.get_name() == func_name: + return func + #for set_name in self.func_sets.keys(): + # func = self.func_sets[set_name].get(func_name) + # if func is not None: + # return func def get_function_set(self,set_name:str = None) -> List[AIFunction]: if set_name is None: diff --git a/src/aios/agent/llm_process.py b/src/aios/agent/llm_process.py index abed5e0..053da6b 100644 --- a/src/aios/agent/llm_process.py +++ b/src/aios/agent/llm_process.py @@ -80,6 +80,9 @@ class BaseLLMProcess(ABC): def _format_content_by_env_value(self,content:str,env)->str: return content.format_map(env) + def prepare_inner_function_context_for_exec(self,inner_func_name:str,parameters:Dict): + return + async def _execute_inner_func(self,inner_func_call_node:Dict,prompt: LLMPrompt,stack_limit = 1) -> ComputeTaskResult: arguments = None stack_limit = stack_limit - 1 @@ -92,7 +95,8 @@ class BaseLLMProcess(ABC): 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) + self.prepare_inner_function_context_for_exec(func_name,arguments) + 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}") @@ -440,9 +444,8 @@ class LLMAgentMessageProcess(BaseLLMProcess): ## 可以使用的tools(inner function)的解释,注意不定义该tips,则不会导入任何workspace中的tools if self.tools_tips: system_prompt_dict["tools_tips"] = self.tools_tips - #prompt.append_system_message(self.tools_tips) - #self.llm_context. + prompt.inner_functions =LLMProcessContext.aifunctions_to_inner_functions(self.llm_context.get_all_ai_functions()) if self.workspace: #TODO eanble workspace functions? logger.info(f"workspace is not none,enable workspace functions") @@ -458,6 +461,8 @@ class LLMAgentMessageProcess(BaseLLMProcess): return prompt + def prepare_inner_function_context_for_exec(self,inner_func_name:str,parameters:Dict): + parameters["_workspace"] = self.workspace async def get_inner_function_for_exec(self,func_name:str) -> AIFunction: return self.llm_context.get_ai_function(func_name) @@ -518,9 +523,30 @@ class ReviewTaskProcess(BaseLLMProcess): return True - async def load_from_config(self, config: dict): + + async def load_from_config(self, config: dict,is_load_default=True) -> Coroutine[Any, Any, bool]: + + if await super().load_from_config(config) is False: return False + + self.role_description = config.get("role_desc") + if self.role_description is None: + logger.error(f"role_description not found in config") + return False + + if config.get("process_description"): + self.process_description = config.get("process_description") + + if config.get("reply_format"): + self.reply_format = config.get("reply_format") + + if config.get("context"): + self.context = config.get("context") + + self.llm_context = SimpleLLMContext() + if config.get("llm_context"): + self.llm_context.load_from_config(config.get("llm_context")) async def prepare_prompt(self,input:Dict) -> LLMPrompt: agent_task = input.get("task") @@ -529,7 +555,8 @@ class ReviewTaskProcess(BaseLLMProcess): system_prompt_dict["role_description"] = self.role_description system_prompt_dict["process_rule"] = self.process_description system_prompt_dict["reply_format"] = self.reply_format - + prompt.append_system_message(json.dumps(system_prompt_dict)) + prompt.append_user_message(json.dumps(agent_task.to_dict())) return prompt diff --git a/src/aios/agent/workflow.py b/src/aios/agent/workflow.py index 8bf692a..b025e76 100644 --- a/src/aios/agent/workflow.py +++ b/src/aios/agent/workflow.py @@ -310,7 +310,7 @@ class Workflow: result_func = [] for inner_func in all_inner_function: - func_name = inner_func.get_name() + func_name = inner_func.get_id() if the_role.enable_function_list is not None: if len(the_role.enable_function_list) > 0: if func_name not in the_role.enable_function_list: diff --git a/src/aios/agent/workspace.py b/src/aios/agent/workspace.py index 37485af..89688ee 100644 --- a/src/aios/agent/workspace.py +++ b/src/aios/agent/workspace.py @@ -8,7 +8,7 @@ from typing import List, Optional import aiofiles -from ..proto.ai_function import AIFunction,SimpleAIFunction,ActionNode,SimpleAIAction +from ..proto.ai_function import AIFunction, ParameterDefine,SimpleAIFunction,ActionNode,SimpleAIAction from ..proto.agent_task import AgentTask,AgentTodoTask,AgentWorkLog,AgentTaskManager from ..storage.storage import AIStorage from .llm_context import GlobaToolsLibrary @@ -77,11 +77,12 @@ class LocalAgentTaskManger(AgentTaskManager): logger.info("create_task at %s",detail_path) async with aiofiles.open(detail_path, mode='w', encoding="utf-8") as f: await f.write(json.dumps(task.to_dict())) + return "create task ok" except Exception as e: logger.error("create_task failed:%s",e) return str(e) - return None + async def create_todos(self,owner_task_id:str,todos:List[AgentTodoTask]): owner_task_path = self._get_obj_path(owner_task_id) @@ -240,7 +241,6 @@ class LocalAgentTaskManger(AgentTaskManager): async def list_task(self,filter:Optional[dict] = None ) -> List[AgentTask]: - directory_path = self.root_path result_list:List[AgentTask] = [] @@ -251,7 +251,7 @@ class LocalAgentTaskManger(AgentTaskManager): continue if entry.name == "workspace": continue - task_item = await self.get_task_by_path(entry.path) + task_item = await self._get_task_by_fullpath(entry.path) if task_item: if not task_item.is_finish(): result_list.append(task_item) @@ -259,8 +259,6 @@ class LocalAgentTaskManger(AgentTaskManager): return result_list - - async def update_task(self,task:AgentTask): detail_path = f"{self.root_path}/{task.task_path}/detail" try: @@ -316,70 +314,68 @@ class AgentWorkspace: def __init__(self,owner_agent_id:str) -> None: self.agent_id : str = owner_agent_id self.task_mgr : AgentTaskManager = LocalAgentTaskManger(owner_agent_id) - self.actions : Dict[str,ActionNode] = {} - self.inner_functions : Dict[str,AIFunction] = {} - #self.init_actions() - #self.init_inner_functions() @staticmethod - def register_actions(): + def register_ai_functions(): async def create_task(params): - _self = params.get("_workspace") - if _self is None: - return "self not found" + _workspace = params.get("_workspace") + if _workspace is None: + return "_workspace not found" taskObj = AgentTask.create_by_dict(params) parent_id = params.get("parent") - return await _self.task_mgr.create_task(taskObj,parent_id) - - create_task_action = SimpleAIAction( + return await _workspace.task_mgr.create_task(taskObj,parent_id) + parameters = ParameterDefine.create_parameters({ + "title": {"type": "string", "description": "task title"}, + "detail": {"type": "string", "description": "task detail(simple task can not be filled)"}, + "tags": {"type": "string", "description": "optional,task tags"}, + "due_date": {"type": "string", "description": "optional,task due date"}, + "parent": {"type": "string", "description": "optional,parent task id"}, + }) + create_task_action = SimpleAIFunction( "agent.workspace.create_task", - "Create a task in the task system, the supported parameters are: title, detail (simple task can not be filled), tags,due_date", + "Create a task", create_task, + parameters, ) - GlobaToolsLibrary.get_instance().register_tool_function(create_task_action) async def cancel_task(parameters): - _self = parameters.get("_workspace") - if _self is None: - return "self not found" + _workspace = parameters.get("_workspace") + if _workspace is None: + return "_workspace not found" task_id = parameters.get("task_id") - task = await _self.task_mgr.get_task(task_id) + task = await _workspace.task_mgr.get_task(task_id) if task is None: return f"task {task_id} not found" task.state = "cancel" - return await _self.task_mgr.update_task(task) - cancel_task_action = SimpleAIAction( + await _workspace.task_mgr.update_task(task) + return "canncel task ok" + + parameters = ParameterDefine.create_parameters({ + "task_id": {"type": "string", "description": "task id which want to cancel"}, + }) + cancel_task_action = SimpleAIFunction( "agent.workspace.cancel_task", "Cancel this task", cancel_task, + parameters ) - GlobaToolsLibrary.get_instance().register_tool_function(create_task_action) + GlobaToolsLibrary.get_instance().register_tool_function(cancel_task_action) - - def get_actions(self) -> Dict: - return self.actions - - def init_inner_functions(self): - async def list_tasks(): - result = {} - fitler = {} - task_list = await self.task_mgr.list_task(fitler) - for task_item in task_list: - result[task_item.task_id] = task_item.title - - return json.dumps(result) - - self.inner_functions["list_tasks"] = SimpleAIFunction("list_tasks", - "list all tasks in json format like {{$task_id:$task_title}...}", - list_tasks) - def get_inner_function_desc(self) -> List[AIFunction]: - func_list = [] - func_list.extend(self.inner_functions.values()) - return func_list - - def get_actions_for_task_review(self) -> Dict: - return self.actions \ No newline at end of file + async def list_task(parameters): + _workspace = parameters.get("_workspace") + if _workspace is None: + return "_workspace not found" + all_task = await _workspace.task_mgr.list_task(None) + if all_task: + return json.dumps([task.to_dict() for task in all_task]) + else : + return "no task" + list_task_ai_function = SimpleAIFunction("agent.workspace.list_task", + "list all tasks in json format", + list_task,{}) + GlobaToolsLibrary.get_instance().register_tool_function(list_task_ai_function) + \ No newline at end of file diff --git a/src/aios/ai_functions/asr_function.py b/src/aios/ai_functions/asr_function.py index 95fcb1c..7c729d0 100644 --- a/src/aios/ai_functions/asr_function.py +++ b/src/aios/ai_functions/asr_function.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) class AsrFunction(AIFunction): def __init__(self): - self.func_id = "aigc.speech_to_text" + self.func_id = "aigc.voice_to_text" self.description = "Voice recognition, convert the voice into text" self.parameters = ParameterDefine.create_parameters({ "audio_file": {"type": "string", "description": "Audio file path"}, @@ -22,7 +22,7 @@ class AsrFunction(AIFunction): def register_function(self): GlobaToolsLibrary.get_instance().register_tool_function(self) - def get_name(self) -> str: + def get_id(self) -> str: return self.func_id def get_description(self) -> str: diff --git a/src/aios/ai_functions/duckduckgo_text_search_function.py b/src/aios/ai_functions/duckduckgo_text_search_function.py index 4ded8ff..05fbb9f 100644 --- a/src/aios/ai_functions/duckduckgo_text_search_function.py +++ b/src/aios/ai_functions/duckduckgo_text_search_function.py @@ -9,8 +9,8 @@ from duckduckgo_search import AsyncDDGS class DuckDuckGoTextSearchFunction(AIFunction): def __init__(self): - self.name = "duckduckgo_text_search" - self.description = "Search text from duckduckgo.com" + self.name = "web.search.duckduckgo" + self.description = "Search web by text (powered by DuckDuckGo)" self.region = "wt-wt" self.safesearch = "moderate" self.time = "y" @@ -22,7 +22,7 @@ class DuckDuckGoTextSearchFunction(AIFunction): def register_function(self): GlobaToolsLibrary.get_instance().register_tool_function(self) - def get_name(self) -> str: + def get_id(self) -> str: return self.name def get_description(self) -> str: diff --git a/src/aios/ai_functions/image_2_text_function.py b/src/aios/ai_functions/image_2_text_function.py index 81ba467..f0a61b4 100644 --- a/src/aios/ai_functions/image_2_text_function.py +++ b/src/aios/ai_functions/image_2_text_function.py @@ -21,7 +21,7 @@ class Image2TextFunction(AIFunction): def register_function(self): GlobaToolsLibrary.get_instance().register_tool_function(self) - def get_name(self) -> str: + def get_id(self) -> str: return self.func_id def get_description(self) -> str: diff --git a/src/aios/ai_functions/script_to_speech_function.py b/src/aios/ai_functions/script_to_speech_function.py index e76ddbe..31a11d7 100644 --- a/src/aios/ai_functions/script_to_speech_function.py +++ b/src/aios/ai_functions/script_to_speech_function.py @@ -45,7 +45,7 @@ class ScriptToSpeechFunction(AIFunction): Path(self.speech_path).mkdir(exist_ok=True) - def get_name(self) -> str: + def get_id(self) -> str: return self.func_id def get_description(self) -> str: diff --git a/src/aios/ai_functions/sql_database_function.py b/src/aios/ai_functions/sql_database_function.py index 81dfd17..6fd92c3 100644 --- a/src/aios/ai_functions/sql_database_function.py +++ b/src/aios/ai_functions/sql_database_function.py @@ -26,7 +26,7 @@ class GetTableInfosFunction(AIFunction): self.name = "get_table_infos" self.description = "Get table informations in the database" - def get_name(self) -> str: + def get_id(self) -> str: return self.name def get_description(self) -> str: @@ -74,7 +74,7 @@ class ExecuteSqlFunction(AIFunction): If an error is returned, rewrite the query, check the query, and try again. """ - def get_name(self) -> str: + def get_id(self) -> str: return self.name def get_description(self) -> str: diff --git a/src/aios/ai_functions/text_to_speech_function.py b/src/aios/ai_functions/text_to_speech_function.py index 73d3152..3a555ac 100644 --- a/src/aios/ai_functions/text_to_speech_function.py +++ b/src/aios/ai_functions/text_to_speech_function.py @@ -27,7 +27,7 @@ class TextToSpeechFunction(AIFunction): }) Path(self.speech_path).mkdir(exist_ok=True) - def get_name(self) -> str: + def get_id(self) -> str: return self.func_id def get_description(self) -> str: diff --git a/src/aios/environment/environment.py b/src/aios/environment/environment.py index 22f1fc3..3ccb0e1 100644 --- a/src/aios/environment/environment.py +++ b/src/aios/environment/environment.py @@ -73,7 +73,7 @@ class SimpleEnvironment(BaseEnvironment): self.operations: Dict[str,AIAction] = {} def add_ai_function(self,func:AIFunction) -> None: - self.functions[func.get_name()] = func + self.functions[func.get_id()] = func def get_ai_function(self,func_name:str) -> AIFunction: func = self.functions.get(func_name) @@ -111,7 +111,7 @@ class CompositeEnvironment(SimpleEnvironment): self.envs.append(env) functions = env.get_all_ai_functions() for func in functions: - self.functions[func.get_name()] = func + self.functions[func.get_id()] = func operations = env.get_all_ai_operations() for op in operations: self.operations[op.get_name()] = op diff --git a/src/aios/proto/ai_function.py b/src/aios/proto/ai_function.py index 8e5165a..c0fcad9 100644 --- a/src/aios/proto/ai_function.py +++ b/src/aios/proto/ai_function.py @@ -21,6 +21,13 @@ class ParameterDefine: class AIFunction: + @abstractmethod + def get_id(self) -> str: + """ + return the id of the function (should be snake case) + """ + pass + @abstractmethod def get_name(self) -> str: """ @@ -140,7 +147,7 @@ class AIFunction: return {"type": "object", "properties": {}} @abstractmethod - async def execute(self, **kwargs) -> str: + async def execute(self, arguments:Dict) -> str: """ Execute the function and return a JSON serializable dict by LLM The parameters are passed in the form of kwargs @@ -210,20 +217,23 @@ class SimpleAIFunction(AIFunction): self.func_handler = func_handler self.parameters:Dict[str,ParameterDefine] = parameters - def get_name(self) -> str: + def get_id(self) -> str: return self.func_id + def get_name(self) -> str: + return self.func_id.split('.')[-1].strip() + def get_description(self) -> str: return self.description def get_parameters(self) -> Dict[str,ParameterDefine]: return self.parameters - async def execute(self,**kwargs) -> str: + async def execute(self,parameters:Dict) -> str: if self.func_handler is None: return f"error: function {self.func_id} not implemented" - return await self.func_handler(**kwargs) + return await self.func_handler(parameters) def is_local(self) -> bool: return True @@ -284,7 +294,7 @@ class AIFunction2Action(AIAction): @abstractmethod def get_name(self) -> str: - return self.func.get_name() + return self.func.get_id() @abstractmethod def get_description(self) -> str: diff --git a/src/service/aios_shell/aios_shell.py b/src/service/aios_shell/aios_shell.py index 765de93..1ce1740 100644 --- a/src/service/aios_shell/aios_shell.py +++ b/src/service/aios_shell/aios_shell.py @@ -19,8 +19,6 @@ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from prompt_toolkit.completion import WordCompleter from prompt_toolkit.styles import Style - - directory = os.path.dirname(__file__) sys.path.append(directory + '/../../') @@ -149,6 +147,7 @@ class AIOS_Shell: #AgentManager.get_instance().register_environment("bash", ShellEnvironment) #AgentManager.get_instance().register_environment("fs", FilesystemEnvironment) #AgentManager.get_instance().register_environment("knowledge", LocalKnowledgeBase) + AgentWorkspace.register_ai_functions() if await AgentManager.get_instance().initial() is not True: logger.error("agent manager initial failed!")