openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
142 lines (141 loc) • 7.4 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-6kR-86XC.mjs";
import { A as parseAgentSessionKey } from "./session-key-BC4m_Ly5.mjs";
import { t as ADMIN_SCOPE } from "./operator-scopes-D-CL26h0.mjs";
import { i as GATEWAY_CLIENT_NAMES, r as GATEWAY_CLIENT_MODES } from "./client-info-S_xwnr2o.mjs";
import { t as INTERNAL_MESSAGE_CHANNEL } from "./message-channel-constants-Dq-VU_KZ.mjs";
import { n as normalizeMessageChannel } from "./message-channel-core-JDeu-bNU.mjs";
import { i as isGatewayCliClient, l as isWebchatClient } from "./message-channel-BCUrZuO3.mjs";
import { r as sessionDeliveryOrigin, t as deliveryContextFromSession } from "./delivery-context.read-CR06zOJ4.mjs";
import "./method-scopes-C-MKLkWf.mjs";
import { n as isPluginOwnedSessionBindingRecord } from "./conversation-binding-metadata-CFOhDjMh.mjs";
import { t as getSessionBindingService } from "./session-binding-service-BxjdmbUW.mjs";
import { t as sanitizeChatSendMessageInput } from "./chat-input-sanitize-BUL6M46s.mjs";
//#region src/gateway/server-methods/chat-origin-routing.ts
const CHANNEL_AGNOSTIC_SESSION_SCOPES = /* @__PURE__ */ new Set([
"main",
"direct",
"dm",
"group",
"channel",
"cron",
"run",
"subagent",
"acp",
"thread",
"topic"
]);
const CHANNEL_SCOPED_SESSION_SHAPES = /* @__PURE__ */ new Set([
"direct",
"dm",
"group",
"channel"
]);
function normalizeExplicitChatSendOrigin(params) {
const originatingChannel = normalizeOptionalString(params.originatingChannel);
const originatingTo = normalizeOptionalString(params.originatingTo);
const accountId = normalizeOptionalString(params.accountId);
const messageThreadId = normalizeOptionalString(params.messageThreadId);
if (!Boolean(originatingChannel || originatingTo || accountId || messageThreadId)) return { ok: true };
const normalizedChannel = normalizeMessageChannel(originatingChannel);
if (!normalizedChannel) return {
ok: false,
error: "originatingChannel is required when using originating route fields"
};
if (!originatingTo) return {
ok: false,
error: "originatingTo is required when using originating route fields"
};
return {
ok: true,
value: {
originatingChannel: normalizedChannel,
originatingTo,
...accountId ? { accountId } : {},
...messageThreadId ? { messageThreadId } : {}
}
};
}
function resolveChatSendOriginatingRoute(params) {
if (params.explicitOrigin?.originatingChannel && params.explicitOrigin.originatingTo) return {
originatingChannel: params.explicitOrigin.originatingChannel,
originatingTo: params.explicitOrigin.originatingTo,
...params.explicitOrigin.accountId ? { accountId: params.explicitOrigin.accountId } : {},
...params.explicitOrigin.messageThreadId ? { messageThreadId: params.explicitOrigin.messageThreadId } : {},
explicitDeliverRoute: params.deliver === true
};
const internalRoute = {
originatingChannel: INTERNAL_MESSAGE_CHANNEL,
originatingTo: params.sessionKey,
explicitDeliverRoute: false
};
if (params.deliver !== true) return internalRoute;
const sessionDeliveryContext = deliveryContextFromSession(params.entry);
const sessionOrigin = sessionDeliveryOrigin(params.entry);
const routeChannelCandidate = normalizeMessageChannel(sessionDeliveryContext?.channel ?? sessionOrigin?.provider);
const routeToCandidate = sessionDeliveryContext?.to;
const routeAccountIdCandidate = sessionDeliveryContext?.accountId ?? sessionOrigin?.accountId;
const routeThreadIdCandidate = sessionDeliveryContext?.threadId ?? sessionOrigin?.threadId;
if (params.sessionKey.length > 512) return internalRoute;
const sessionScopeParts = (parseAgentSessionKey(params.sessionKey)?.rest ?? params.sessionKey).split(":", 3).filter(Boolean);
const sessionScopeHead = sessionScopeParts[0];
const sessionChannelHint = normalizeMessageChannel(sessionScopeHead);
const normalizedSessionScopeHead = (sessionScopeHead ?? "").trim().toLowerCase();
const sessionPeerShapeCandidates = [sessionScopeParts[1], sessionScopeParts[2]].map((part) => (part ?? "").trim().toLowerCase()).filter(Boolean);
const isChannelAgnosticSessionScope = CHANNEL_AGNOSTIC_SESSION_SCOPES.has(normalizedSessionScopeHead);
const isChannelScopedSession = sessionPeerShapeCandidates.some((part) => CHANNEL_SCOPED_SESSION_SHAPES.has(part));
const hasLegacyChannelPeerShape = !isChannelScopedSession && typeof sessionScopeParts[1] === "string" && sessionChannelHint === routeChannelCandidate;
const isFromWebchatClient = isWebchatClient(params.client);
const isFromGatewayCliClient = isGatewayCliClient(params.client);
const hasClientMetadata = typeof params.client?.mode === "string" && params.client.mode.trim().length > 0 || typeof params.client?.id === "string" && params.client.id.trim().length > 0;
const configuredMainKey = (params.mainKey ?? "main").trim().toLowerCase();
const canInheritConfiguredMainRoute = normalizedSessionScopeHead.length > 0 && normalizedSessionScopeHead === configuredMainKey && params.hasConnectedClient && (isFromGatewayCliClient || !hasClientMetadata);
if (!(Boolean(!isFromWebchatClient && sessionChannelHint && sessionChannelHint !== "webchat" && (!isChannelAgnosticSessionScope && (isChannelScopedSession || hasLegacyChannelPeerShape) || canInheritConfiguredMainRoute)) && routeChannelCandidate && routeChannelCandidate !== "webchat" && typeof routeToCandidate === "string" && routeToCandidate.trim().length > 0)) return internalRoute;
return {
originatingChannel: routeChannelCandidate,
originatingTo: routeToCandidate,
accountId: routeAccountIdCandidate,
messageThreadId: routeThreadIdCandidate,
explicitDeliverRoute: true
};
}
function isAcpSessionKey(sessionKey) {
return Boolean(sessionKey?.split(":").includes("acp"));
}
function resolveExplicitOriginBinding(origin) {
if (!origin?.originatingChannel || !origin.originatingTo || !origin.accountId) return;
const channel = normalizeMessageChannel(origin.originatingChannel);
if (!channel || channel === "webchat") return;
return getSessionBindingService().resolveByConversation({
channel,
accountId: origin.accountId,
conversationId: origin.originatingTo
});
}
function explicitOriginTargetsAcpSession(origin) {
return isAcpSessionKey(resolveExplicitOriginBinding(origin)?.targetSessionKey);
}
function explicitOriginTargetsPluginBinding(origin) {
return isPluginOwnedSessionBindingRecord(resolveExplicitOriginBinding(origin));
}
function normalizeOptionalChatSystemReceipt(value) {
if (value == null) return { ok: true };
if (typeof value !== "string") return {
ok: false,
error: "systemProvenanceReceipt must be a string"
};
const sanitized = sanitizeChatSendMessageInput(value);
if (!sanitized.ok) return sanitized;
return {
ok: true,
receipt: sanitized.message.trim() || void 0
};
}
function isAcpBridgeClient(client) {
const info = client?.connect?.client;
return info?.id === GATEWAY_CLIENT_NAMES.CLI && info?.mode === GATEWAY_CLIENT_MODES.CLI && info?.displayName === "ACP" && info?.version === "acp";
}
function hasGatewayAdminScope(client) {
return (Array.isArray(client?.connect?.scopes) ? client.connect.scopes : []).includes(ADMIN_SCOPE);
}
//#endregion
export { normalizeExplicitChatSendOrigin as a, isAcpBridgeClient as i, explicitOriginTargetsPluginBinding as n, normalizeOptionalChatSystemReceipt as o, hasGatewayAdminScope as r, resolveChatSendOriginatingRoute as s, explicitOriginTargetsAcpSession as t };