98 lines
3.3 KiB
Python
98 lines
3.3 KiB
Python
"""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
|