第一次提交
This commit is contained in:
6
app-instance/backend/nanobot/bus/__init__.py
Normal file
6
app-instance/backend/nanobot/bus/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
"""Message bus module for decoupled channel-agent communication."""
|
||||
|
||||
from nanobot.bus.events import InboundMessage, OutboundMessage
|
||||
from nanobot.bus.queue import MessageBus
|
||||
|
||||
__all__ = ["MessageBus", "InboundMessage", "OutboundMessage"]
|
||||
38
app-instance/backend/nanobot/bus/events.py
Normal file
38
app-instance/backend/nanobot/bus/events.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""Event types for the message bus."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class InboundMessage:
|
||||
"""Message received from a chat channel."""
|
||||
|
||||
channel: str # telegram, discord, slack, whatsapp
|
||||
sender_id: str # User identifier
|
||||
chat_id: str # Chat/channel identifier
|
||||
content: str # Message text
|
||||
timestamp: datetime = field(default_factory=datetime.now)
|
||||
media: list[str] = field(default_factory=list) # Media URLs
|
||||
metadata: dict[str, Any] = field(default_factory=dict) # Channel-specific data
|
||||
session_key_override: str | None = None # Optional override for thread-scoped sessions
|
||||
|
||||
@property
|
||||
def session_key(self) -> str:
|
||||
"""Unique key for session identification."""
|
||||
return self.session_key_override or f"{self.channel}:{self.chat_id}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class OutboundMessage:
|
||||
"""Message to send to a chat channel."""
|
||||
|
||||
channel: str
|
||||
chat_id: str
|
||||
content: str
|
||||
reply_to: str | None = None
|
||||
media: list[str] = field(default_factory=list)
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
77
app-instance/backend/nanobot/bus/queue.py
Normal file
77
app-instance/backend/nanobot/bus/queue.py
Normal file
@ -0,0 +1,77 @@
|
||||
"""消息总线(MessageBus):用异步队列解耦“渠道层”和“Agent 核心层”。
|
||||
|
||||
核心思想:
|
||||
1. 渠道(Telegram/Discord/CLI 等)只负责收发消息,不直接调用 Agent 内部逻辑
|
||||
2. Agent 只关心“从入站队列取消息、处理后写回出站队列”
|
||||
3. 通过队列实现生产者/消费者解耦,提升并发稳定性与可维护性
|
||||
|
||||
为什么需要两个队列:
|
||||
- inbound:渠道 -> Agent
|
||||
- outbound:Agent -> 渠道
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from nanobot.bus.events import InboundMessage, OutboundMessage
|
||||
|
||||
|
||||
class MessageBus:
|
||||
"""
|
||||
异步消息总线。
|
||||
|
||||
典型流转:
|
||||
- 渠道监听到用户消息后调用 `publish_inbound`
|
||||
- Agent 主循环调用 `consume_inbound` 拿到消息并处理
|
||||
- Agent 产出回复后调用 `publish_outbound`
|
||||
- 渠道管理器调用 `consume_outbound` 并把回复发送到对应平台
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# 入站队列:存放所有“用户 -> Agent”的消息事件。
|
||||
self.inbound: asyncio.Queue[InboundMessage] = asyncio.Queue()
|
||||
# 出站队列:存放所有“Agent -> 用户”的回复事件。
|
||||
self.outbound: asyncio.Queue[OutboundMessage] = asyncio.Queue()
|
||||
|
||||
async def publish_inbound(self, msg: InboundMessage) -> None:
|
||||
"""发布入站消息(由渠道层调用)。
|
||||
|
||||
参数:
|
||||
- msg: 一个 InboundMessage,包含 channel/sender/chat_id/content 等信息
|
||||
"""
|
||||
# put 是异步的:当队列受限时可自然背压;当前默认无长度上限。
|
||||
await self.inbound.put(msg)
|
||||
|
||||
async def consume_inbound(self) -> InboundMessage:
|
||||
"""消费下一条入站消息(由 Agent 主循环调用)。
|
||||
|
||||
行为:
|
||||
- 若队列为空会等待(阻塞当前协程,不阻塞事件循环)
|
||||
"""
|
||||
return await self.inbound.get()
|
||||
|
||||
async def publish_outbound(self, msg: OutboundMessage) -> None:
|
||||
"""发布出站消息(由 Agent 调用)。
|
||||
|
||||
参数:
|
||||
- msg: 一个 OutboundMessage,包含目标 channel/chat_id 与内容
|
||||
"""
|
||||
await self.outbound.put(msg)
|
||||
|
||||
async def consume_outbound(self) -> OutboundMessage:
|
||||
"""消费下一条出站消息(由渠道分发器调用)。
|
||||
|
||||
行为:
|
||||
- 若队列为空会等待,直到 Agent 写入新的回复
|
||||
"""
|
||||
return await self.outbound.get()
|
||||
|
||||
@property
|
||||
def inbound_size(self) -> int:
|
||||
"""当前入站队列长度(待处理消息数)。"""
|
||||
# 常用于监控/调试:判断是否出现消息堆积。
|
||||
return self.inbound.qsize()
|
||||
|
||||
@property
|
||||
def outbound_size(self) -> int:
|
||||
"""当前出站队列长度(待发送回复数)。"""
|
||||
return self.outbound.qsize()
|
||||
Reference in New Issue
Block a user