from abc import ABC, abstractmethod from typing import AsyncIterator, Dict, Any from gateway.protocol import UserMessage, AgentMessage, ChannelStatus class Channel(ABC): """Abstract base class for communication channels. Channels are the transport layer between users and the agent system. They handle protocol-specific encoding/decoding and maintain connection state. """ def __init__(self, channel_id: str, channel_type: str): self.channel_id = channel_id self.channel_type = channel_type self._connected = False @abstractmethod async def send(self, message: AgentMessage) -> None: """Send a message from the agent to the user through this channel. Args: message: AgentMessage to send (may be streaming chunk or complete message) """ pass @abstractmethod async def receive(self) -> AsyncIterator[UserMessage]: """Receive messages from the user through this channel. Yields: UserMessage objects as they arrive """ pass @abstractmethod async def close(self) -> None: """Close the channel and clean up resources.""" pass def supports_streaming(self) -> bool: """Whether this channel supports streaming responses. Returns: True if the channel can handle streaming chunks """ return False def supports_attachments(self) -> bool: """Whether this channel supports file attachments. Returns: True if the channel can handle attachments """ return False def get_status(self) -> ChannelStatus: """Get current channel status. Returns: ChannelStatus object with connection info and capabilities """ return ChannelStatus( channel_id=self.channel_id, channel_type=self.channel_type, connected=self._connected, capabilities={ "streaming": self.supports_streaming(), "attachments": self.supports_attachments(), "markdown": True # Most channels support some form of markdown } )