"""In-memory channel adapter for tests and local gateway embedding.""" from __future__ import annotations from typing import Any from beaver.foundation.events import InboundMessage, MessageBus, OutboundMessage class MemoryChannelAdapter: """A local channel that stores outbound messages in memory.""" def __init__(self, bus: MessageBus, *, name: str = "memory") -> None: self.name = name self.bus = bus 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, metadata: dict[str, Any] | None = None, ) -> InboundMessage: """Publish a text message from this channel into the shared bus.""" message = InboundMessage( channel=self.name, 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, metadata=metadata or {}, ) await self.bus.publish_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. """ session_parts = [self.name, chat_id] if thread_id: session_parts.append(thread_id) 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, session_id=":".join(str(part) for part in session_parts if str(part)), user_id=user_id, title=title, metadata=metadata, )