"""In-memory channel adapter for tests and local gateway embedding.""" from __future__ import annotations from typing import Any from beaver.foundation.events import ChannelIdentity, InboundMessage, OutboundMessage from beaver.interfaces.channels.base import ChannelInboundSink class MemoryChannelAdapter: """A local channel that stores outbound messages in memory.""" def __init__( self, inbound_sink: ChannelInboundSink, *, channel_id: str = "memory-dev", kind: str = "memory", mode: str = "webhook", account_id: str = "memory", ) -> None: self.channel_id = channel_id self.kind = kind self.mode = mode self.account_id = account_id self.inbound_sink = inbound_sink self.started = False self.sent_messages: list[OutboundMessage] = [] async def start(self) -> None: self.started = True async def stop(self) -> None: self.started = False async def send(self, message: OutboundMessage) -> None: self.sent_messages.append(message) async def publish_text( self, content: str, *, session_id: str | None = None, user_id: str | None = None, title: str | None = None, execution_context: str | None = None, model: str | None = None, provider_name: str | None = None, embedding_model: str | None = None, peer_id: str = "default", thread_id: str | None = None, message_id: str | None = None, metadata: dict[str, Any] | None = None, ) -> InboundMessage: """Publish a text message from this channel into the shared bus.""" identity = ChannelIdentity( channel_id=self.channel_id, kind=self.kind, account_id=self.account_id, peer_id=peer_id, thread_id=thread_id, user_id=user_id, message_id=message_id, ) message = InboundMessage( channel=self.channel_id, content=content, session_id=session_id, user_id=user_id, title=title, execution_context=execution_context, model=model, provider_name=provider_name, embedding_model=embedding_model, channel_identity=identity, metadata=metadata or {}, ) await self.inbound_sink.accept_inbound(message) return message async def publish_external_text( self, content: str, *, chat_id: str, message_id: str | None = None, thread_id: str | None = None, raw_payload: dict[str, Any] | None = None, user_id: str | None = None, title: str | None = None, ) -> InboundMessage: """Publish an old-style channel payload through the new adapter contract. Real platform adapters should keep platform-specific fields here, build a stable Beaver session_id, and pass the normalized InboundMessage to the shared gateway bus. """ metadata = { "chat_id": chat_id, "message_id": message_id, "thread_id": thread_id, "raw_channel_payload": raw_payload or {}, } return await self.publish_text( content, user_id=user_id, title=title, peer_id=chat_id, thread_id=thread_id, message_id=message_id, metadata=metadata, )