feat: implement channel runtime connectors
This commit is contained in:
@ -0,0 +1,97 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user