"""Generic runtime channel backed by an external connector sidecar.""" from __future__ import annotations import hashlib from typing import Any from beaver.foundation.events import OutboundMessage from beaver.interfaces.channels.connections.sidecar_client import ConnectorSidecarClient class ExternalConnectorChannel: def __init__( self, *, channel_id: str, platform_kind: str, connection_id: str, account_id: str, display_name: str, sidecar_client: ConnectorSidecarClient | Any, ) -> None: self.channel_id = channel_id self.kind = "external_connector" self.mode = "http" self.platform_kind = platform_kind self.connection_id = connection_id self.account_id = account_id self.display_name = display_name or channel_id self.sidecar_client = sidecar_client self.started = False async def start(self) -> None: self.started = True async def stop(self) -> None: self.started = False async def send(self, message: OutboundMessage) -> None: identity = message.channel_identity if identity is None: raise ValueError("channel_identity is required for external connector sends") metadata = { "inboundMessageId": identity.message_id, "sessionId": message.session_id, } context_token = _context_token(message) if context_token: metadata["contextToken"] = context_token payload = { "requestId": _request_id(message), "connectionId": self.connection_id, "channelId": self.channel_id, "kind": self.platform_kind, "target": { "peerId": identity.peer_id, "peerType": identity.peer_type, "threadId": identity.thread_id, }, "content": message.content, "metadata": metadata, } await self.sidecar_client.send(payload) def _request_id(message: OutboundMessage) -> str: identity = message.channel_identity channel = message.channel or (identity.channel_id if identity else "unknown") session_id = message.session_id or (identity.session_id() if identity else "unknown") message_id = str(message.message_id or "").strip() if not message_id: basis = "|".join( [ message.content, identity.message_id if identity and identity.message_id else "", identity.peer_id if identity else "", message.finish_reason, ] ) message_id = hashlib.sha256(basis.encode("utf-8")).hexdigest()[:24] return f"out_{channel}:{session_id}:{message_id}" def _context_token(message: OutboundMessage) -> str | None: inbound_metadata = message.metadata.get("inbound_metadata") if isinstance(inbound_metadata, dict): value = _clean_optional(inbound_metadata.get("contextToken") or inbound_metadata.get("context_token")) if value: return value return _clean_optional(message.metadata.get("contextToken") or message.metadata.get("context_token")) def _clean_optional(value: Any) -> str | None: if value is None: return None text = str(value).strip() return text or None