Files
opendan/src/aios_kernel/bus.py
T

149 lines
4.9 KiB
Python
Raw Normal View History

2023-09-14 01:50:18 -07:00
from typing import Coroutine,Dict,Any
2023-10-18 11:19:11 -07:00
from .agent_base import AgentMsg,AgentMsgStatus,AgentMsgType
import asyncio
from asyncio import Queue
import logging
logger = logging.getLogger(__name__)
class AIBusHandler:
2023-09-14 01:50:18 -07:00
def __init__(self,handler:Coroutine,owner_bus,enable_defualt_proc=True) -> None:
self.handler = handler
self.working_task = None
2023-09-14 01:50:18 -07:00
self.results = {} # recv resps
self.queue:Queue = Queue()
2023-09-14 01:50:18 -07:00
self.enable_defualt_proc = enable_defualt_proc
self.owner_bus = owner_bus
async def handle_message(self,msg:AgentMsg) -> Any:
if self.handler is None:
return None
2023-09-22 00:09:21 +08:00
2023-09-14 01:50:18 -07:00
resp_msg = await self.handler(msg)
if self.enable_defualt_proc:
if resp_msg is not None:
if resp_msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
await self.owner_bus.post_message(resp_msg,resp_msg.target)
else:
await self.owner_bus.post_message(resp_msg)
2023-09-14 01:50:18 -07:00
return resp_msg
2023-09-22 00:09:21 +08:00
class AIBus:
_instance = None
@classmethod
def get_default_bus(cls):
if cls._instance is None:
cls._instance = AIBus()
return cls._instance
def __init__(self) -> None:
2023-09-14 01:50:18 -07:00
self.handlers:Dict[AIBusHandler] = {}
self.unhandle_handler:Coroutine = None
async def post_message(self,msg:AgentMsg,target_id = None,use_unhandle=True) -> bool:
if target_id is None:
target_id =msg.target
target_id = target_id.split(".")[0]
2023-09-14 01:50:18 -07:00
handler = self.handlers.get(target_id)
if handler:
2023-09-19 21:36:56 -07:00
if msg.rely_msg_id is not None:
handler.results[msg.rely_msg_id] = msg
return None
2023-09-22 00:09:21 +08:00
handler.queue.put_nowait(msg)
self.start_process(target_id)
return True
2023-09-22 00:09:21 +08:00
if use_unhandle:
if self.unhandle_handler is not None:
if await self.unhandle_handler(self,target_id):
return await self.post_message(msg,target_id,False)
2023-09-22 00:09:21 +08:00
logger.warn(f"post message to {msg.target} failed!,target not found")
return False
2023-09-14 01:50:18 -07:00
async def resp_message(self,org_msg_id:str,resp:AgentMsg) -> None:
assert resp.rely_msg_id == org_msg_id
return await self.post_message(resp)
async def send_message(self,msg:AgentMsg,target_id = None, real_sender=None) -> AgentMsg:
if real_sender is None:
sender_id = msg.sender.split(".")[0]
else:
sender_id = real_sender.split(".")[0]
2023-09-14 01:50:18 -07:00
sender_handler = self.handlers.get(sender_id) # sender already register on bus
if sender_handler is None:
logger.warn(f"sender {sender_id} not register on AI_BUS!")
return None
2023-09-22 00:09:21 +08:00
post_result = await self.post_message(msg,target_id)
if post_result is False:
return None
2023-09-14 01:50:18 -07:00
retry_times = 0
while True:
2023-09-26 18:46:26 -07:00
resp : AgentMsg = sender_handler.results.get(msg.msg_id)
if resp is not None:
msg.resp_msg = resp
2023-09-14 01:50:18 -07:00
msg.status = AgentMsgStatus.RESPONSED
del sender_handler.results[msg.msg_id]
return resp
2023-09-22 00:09:21 +08:00
await asyncio.sleep(0.2)
retry_times += 1
2023-09-22 00:09:21 +08:00
if retry_times > 5*240: # default timeout is 240 sec
2023-09-14 01:50:18 -07:00
msg.status = AgentMsgStatus.ERROR
return None
2023-09-22 00:09:21 +08:00
return None
2023-09-22 00:09:21 +08:00
def register_unhandle_message_handler(self,handler:Any) -> Queue:
self.unhandle_handler = handler
# means sub
2023-09-22 00:09:21 +08:00
def register_message_handler(self,handler_name:str,handler:Any) -> Queue:
handler_node = AIBusHandler(handler,self)
if self.handlers.get(handler_name) is not None:
logger.warn(f"handler {handler_name} already register on AI_BUS!")
self.handlers[handler_name] = handler_node
return handler_node.queue
2023-09-22 00:09:21 +08:00
async def process_queue(self, handler:AIBusHandler):
while True:
# Wait for a message
message = await handler.queue.get()
2023-09-22 00:09:21 +08:00
try:
# Try to handle the message
2023-09-22 00:09:21 +08:00
await handler.handle_message(message)
except Exception as e:
# If an error occurs, put the message back into the queue
2023-09-22 00:09:21 +08:00
logger.error(f"handle message {message.msg_id} failed! {e}")
logger.exception(e)
raise e
#self.queues[name].put_nowait(message)
2023-09-22 00:09:21 +08:00
return
def start_process(self,target_name):
handler = self.handlers.get(target_name)
if handler is None:
logger.error(f"handler {target_name} not found!")
return
2023-09-22 00:09:21 +08:00
if handler.handler is None:
return
if handler.working_task is not None:
logger.warn(f"handler {target_name} is already working!")
return
2023-09-22 00:09:21 +08:00
handler.working_task = asyncio.create_task(self.process_queue(handler))