aios shell support /connect command , connect to a agent though tunnel easy.

This commit is contained in:
Liu Zhicong
2023-09-19 15:43:17 -07:00
parent feca072a4f
commit 298ee73a6b
4 changed files with 123 additions and 19 deletions
+2 -2
View File
@@ -14,11 +14,11 @@ class ResourceLocation:
pass pass
class UserConfigItem: class UserConfigItem:
def __init__(self) -> None: def __init__(self,desc:str=None) -> None:
self.default_value = None self.default_value = None
self.is_optional = False self.is_optional = False
self.item_type = "str" self.item_type = "str"
self.desc = None self.desc = desc
self.value = None self.value = None
self.user_set = False self.user_set = False
+2 -2
View File
@@ -68,7 +68,7 @@ class TelegramTunnel(AgentTunnel):
logger.warning(f"tunnel {self.tunnel_id} is already started") logger.warning(f"tunnel {self.tunnel_id} is already started")
return False return False
self.is_start = True self.is_start = True
logger.warning(f"tunnel {self.tunnel_id} is starting...") logger.info(f"tunnel {self.tunnel_id} is starting...")
self.bot = Bot(self.tg_token) self.bot = Bot(self.tg_token)
self.update_queue = asyncio.Queue() self.update_queue = asyncio.Queue()
@@ -92,7 +92,7 @@ class TelegramTunnel(AgentTunnel):
update_id += 1 update_id += 1
asyncio.create_task(_run_app()) asyncio.create_task(_run_app())
logger.warning(f"tunnel {self.tunnel_id} started.") logger.info(f"tunnel {self.tunnel_id} started.")
return True return True
async def close(self) -> None: async def close(self) -> None:
+28 -1
View File
@@ -13,9 +13,32 @@ class AgentTunnel(ABC):
def register_loader(cls,tunnel_type:str,loader:Coroutine) -> None: def register_loader(cls,tunnel_type:str,loader:Coroutine) -> None:
cls._all_loader[tunnel_type] = loader cls._all_loader[tunnel_type] = loader
@classmethod @classmethod
async def load_all_tunnels_from_config(cls,config:dict) -> None: async def load_all_tunnels_from_config(cls,config:dict) -> None:
for tunnel_config in config: for tunnel_id,tunnel_config in config.items():
loader = cls._all_loader.get(tunnel_config["type"])
tid = tunnel_config.get("tunnel_id")
if tid is not None:
if tunnel_id != tid:
logger.warning(f"load tunnel {tunnel_id} error,{tunnel_id} != {tid} in config!")
continue
else:
tunnel_config["tunnel_id"] = tunnel_id
if loader is not None:
tunnel = await loader(tunnel_config)
if tunnel is not None:
cls._all_tunnels[tunnel_id] = tunnel
tunnel.connect_to(AIBus.get_default_bus(),tunnel.target_id)
await tunnel.start()
else:
logger.error(f"load tunnel {tunnel_id} failed")
else:
logger.error(f"load tunnel {tunnel_id} failed,loader not found")
@classmethod
async def load_tunnel_from_config(cls,tunnel_config:dict):
loader = cls._all_loader.get(tunnel_config["type"]) loader = cls._all_loader.get(tunnel_config["type"])
if loader is not None: if loader is not None:
tunnel = await loader(tunnel_config) tunnel = await loader(tunnel_config)
@@ -23,11 +46,15 @@ class AgentTunnel(ABC):
cls._all_tunnels[tunnel.tunnel_id] = tunnel cls._all_tunnels[tunnel.tunnel_id] = tunnel
tunnel.connect_to(AIBus.get_default_bus(),tunnel.target_id) tunnel.connect_to(AIBus.get_default_bus(),tunnel.target_id)
await tunnel.start() await tunnel.start()
return True
else: else:
logger.error(f"load tunnel {tunnel_config['tunnel_id']} failed") logger.error(f"load tunnel {tunnel_config['tunnel_id']} failed")
else: else:
logger.error(f"load tunnel {tunnel_config['type']} failed,loader not found") logger.error(f"load tunnel {tunnel_config['type']} failed,loader not found")
return False
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.tunnel_id = None self.tunnel_id = None
+82 -5
View File
@@ -34,8 +34,9 @@ logger = logging.getLogger(__name__)
shell_style = Style.from_dict({ shell_style = Style.from_dict({
'title': '#87d7ff bold', #RGB 'title': '#87d7ff bold', #RGB
'content': '#007f00 bold', 'content': '#007f00', # resp content
'prompt': '#00FF00', 'prompt': '#00FF00',
'error': '#8F0000 bold'
}) })
@@ -110,12 +111,10 @@ class AIOS_Shell:
try: try:
tunnel_config = toml.load(tunnels_config_path) tunnel_config = toml.load(tunnels_config_path)
if tunnel_config is not None: if tunnel_config is not None:
await AgentTunnel.load_all_tunnels_from_config(tunnel_config["tunnels"]) await AgentTunnel.load_all_tunnels_from_config(tunnel_config)
except Exception as e: 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!")
return True return True
@@ -135,6 +134,50 @@ class AIOS_Shell:
async def _user_process_msg(self,msg:AgentMsg) -> AgentMsg: async def _user_process_msg(self,msg:AgentMsg) -> AgentMsg:
pass pass
async def get_tunnel_config_from_input(self,tunnel_target,tunnel_type):
tunnel_config = {}
tunnel_config["tunnel_id"] = f"{tunnel_type}_2_{tunnel_target}"
tunnel_config["target"] = tunnel_target
intpu_table = {}
tunnel_introduce : str = ""
match tunnel_type:
case "telegram":
tunnel_config["type"] = "TelegramTunnel"
intpu_table["token"] = UserConfigItem("telegram bot token")
case "email":
tunnel_config["type"] = "EmailTunnel"
case _:
error_text = FormattedText([("class:error", f"tunnel type {tunnel_type}not support!")])
print_formatted_text(error_text,style=shell_style)
return None
intro_text = FormattedText([("class:prompt", tunnel_introduce)])
print_formatted_text(intro_text,style=shell_style)
for key,item in intpu_table.items():
user_input = await try_get_input(f"{key} : {item.desc}")
if user_input is None:
return None
tunnel_config[key] = user_input
return tunnel_config
async def append_tunnel_config(self,tunnel_config):
user_data_dir = AIStorage.get_instance().get_myai_dir()
tunnels_config_path = os.path.abspath(f"{user_data_dir}/etc/tunnels.cfg.toml")
try:
all_tunnels = toml.load(tunnels_config_path)
if all_tunnels is not None:
all_tunnels[tunnel_config["tunnel_id"]] = tunnel_config
f = open(tunnels_config_path,"w")
if f:
toml.dump(all_tunnels,f)
except Exception as e:
logger.warning(f"load tunnels config from {tunnels_config_path} failed!")
async def call_func(self,func_name, args): async def call_func(self,func_name, args):
match func_name: match func_name:
case 'send': case 'send':
@@ -158,8 +201,24 @@ class AIOS_Shell:
show_text = FormattedText([("class:title", f"set {key} to {value} success!")]) show_text = FormattedText([("class:title", f"set {key} to {value} success!")])
return show_text return show_text
case 'connect':
show_text = FormattedText([("class:title", "args error, /connect $target telegram | email")])
if len(args) < 1:
return show_text
tunnel_target = args[0]
if len(args) < 2:
tunnel_type = "telegram"
else:
tunnel_type = args[1]
tunnel_config = await self.get_tunnel_config_from_input(tunnel_target,tunnel_type)
if tunnel_config:
if await AgentTunnel.load_tunnel_from_config(tunnel_config):
# append
await self.append_tunnel_config(tunnel_config)
show_text = FormattedText([("class:title", f"connect to {tunnel_target} success!")])
return show_text
case 'open': case 'open':
if len(args) >= 1: if len(args) >= 1:
target_id = args[0] target_id = args[0]
@@ -221,10 +280,28 @@ def parse_function_call(func_string):
else: else:
return None return None
async def try_get_input(desc:str,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":
return user_input
else:
return None
else:
is_ok,err_str = check_func(user_input)
if is_ok:
return user_input
error_text = FormattedText([("class:error", err_str)])
print_formatted_text(error_text,style=shell_style)
return await try_get_input(desc,check_func)
async def get_user_config_from_input(check_result:dict) -> bool: async def get_user_config_from_input(check_result:dict) -> bool:
for key,item in check_result.items(): for key,item in check_result.items():
user_input = await session.prompt_async(f"{key} ({item.desc}) not define! \nPlease input:",style=shell_style) user_input = await try_get_input(f"System config {key} ({item.desc}) not define!")
if len(user_input) > 0: if len(user_input) > 0:
AIStorage.get_instance().get_user_config().set_value(key,user_input) AIStorage.get_instance().get_user_config().set_value(key,user_input)