openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
114 lines (113 loc) • 5.86 kB
JavaScript
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { o as normalizeHyphenSlug } from "./string-normalization-DsCfAx8q.js";
import { D as normalizeSessionPeerId } from "./session-key-BnWWjqNc.js";
import { r as listDeliverableMessageChannels } from "./message-channel-normalize-B81s0XMO.js";
import "./message-channel-BQrhwUEA.js";
import { i as listChannelPlugins } from "./registry-Cz6cv4VC.js";
//#region src/config/sessions/group.ts
const getGroupSurfaces = () => /* @__PURE__ */ new Set([...listDeliverableMessageChannels(), "webchat"]);
function resolveLegacyGroupSessionKey(ctx) {
for (const plugin of listChannelPlugins()) {
const resolved = plugin.messaging?.resolveLegacyGroupSessionKey?.(ctx);
if (resolved) return resolved;
}
return null;
}
function normalizeGroupLabel(raw) {
return normalizeHyphenSlug(raw);
}
function joinOpaqueTail(parts, start) {
return normalizeOptionalString(parts[start]) ? parts.slice(start).join(":") : null;
}
function resolveOriginatingGroupTargetId(params) {
const target = normalizeOptionalString(params.ctx.OriginatingTo ?? params.ctx.To) ?? "";
if (!target) return null;
const parts = target.split(":");
if (parts.length < 2) return null;
const head = normalizeLowercaseStringOrEmpty(parts[0]);
const second = normalizeOptionalLowercaseString(parts[1]);
if ((second === "group" || second === "channel") && (head === params.provider || getGroupSurfaces().has(head))) return joinOpaqueTail(parts, 2);
if (head === params.provider || head === "chat" || head === "room" || head === "group") return joinOpaqueTail(parts, 1);
if (head === "channel") return joinOpaqueTail(parts, 1);
return null;
}
function shortenGroupId(value) {
const trimmed = normalizeOptionalString(value) ?? "";
if (!trimmed) return "";
if (trimmed.length <= 14) return trimmed;
return `${trimmed.slice(0, 6)}...${trimmed.slice(-4)}`;
}
/**
* Builds a human-readable group/channel title from stored chat metadata.
* Prefers the native channel name (#general) or the chat subject verbatim;
* returns undefined when only opaque route ids are available so callers can
* fall back to the compact token form below.
*/
function buildGroupDisplayTitle(params) {
const subject = normalizeOptionalString(params.subject);
const groupChannel = normalizeOptionalString(params.groupChannel);
const space = normalizeOptionalString(params.space);
if (groupChannel) {
const channelLabel = groupChannel.startsWith("#") ? groupChannel : `#${groupChannel}`;
return space ? `${space} ${channelLabel}` : channelLabel;
}
return subject ?? space ?? void 0;
}
/** Builds a compact display label for group sessions from channel metadata or ids. */
function buildGroupDisplayName(params) {
const providerKey = normalizeOptionalLowercaseString(params.provider) ?? "group";
const groupChannel = normalizeOptionalString(params.groupChannel);
const space = normalizeOptionalString(params.space);
const subject = normalizeOptionalString(params.subject);
const detail = (groupChannel && space ? `${space}${groupChannel.startsWith("#") ? "" : "#"}${groupChannel}` : groupChannel || subject || space || "") || "";
const fallbackId = normalizeOptionalString(params.id) ?? params.key;
const rawLabel = detail || fallbackId;
let token = normalizeGroupLabel(rawLabel);
if (!token) token = normalizeGroupLabel(shortenGroupId(rawLabel));
if (!params.groupChannel && token.startsWith("#")) token = token.replace(/^#+/, "");
if (token && !/^[@#]/.test(token) && !token.startsWith("g-") && !token.includes("#")) token = `g-${token}`;
return token ? `${providerKey}:${token}` : providerKey;
}
/**
* Resolves channel/group chat context into the persisted group session key.
*
* Provider-prefixed ids use channel-owned normalization, while legacy plugin resolvers remain a
* fallback for older channel surfaces that cannot yet express the generic route shape.
*/
function resolveGroupSessionKey(ctx) {
const from = normalizeOptionalString(ctx.From) ?? "";
const chatType = normalizeOptionalLowercaseString(ctx.ChatType);
const normalizedChatType = chatType === "channel" ? "channel" : chatType === "group" ? "group" : void 0;
const legacyResolution = resolveLegacyGroupSessionKey(ctx);
if (!(normalizedChatType === "group" || normalizedChatType === "channel" || from.includes(":group:") || from.includes(":channel:") || legacyResolution !== null)) return null;
const providerHint = normalizeOptionalLowercaseString(ctx.Provider);
const parts = from.split(":");
const head = normalizeLowercaseStringOrEmpty(parts[0]);
const headIsSurface = head ? getGroupSurfaces().has(head) : false;
if (!headIsSurface && !providerHint && legacyResolution) return legacyResolution;
const provider = headIsSurface ? head : providerHint ?? legacyResolution?.channel;
if (!provider) return null;
const second = normalizeOptionalLowercaseString(parts[1]);
const secondIsKind = second === "group" || second === "channel";
const kind = secondIsKind ? second : from.includes(":channel:") || normalizedChatType === "channel" ? "channel" : "group";
const originatingGroupTargetId = !secondIsKind && normalizedChatType ? resolveOriginatingGroupTargetId({
ctx,
provider
}) : null;
const id = originatingGroupTargetId ? originatingGroupTargetId : headIsSurface ? secondIsKind ? joinOpaqueTail(parts, 2) : joinOpaqueTail(parts, 1) : from;
if (!id) return null;
const finalId = normalizeSessionPeerId({
channel: provider,
peerKind: kind,
peerId: id
});
if (!finalId) return null;
return {
key: `${provider}:${kind}:${finalId}`,
channel: provider,
id: finalId,
chatType: kind === "channel" ? "channel" : "group"
};
}
//#endregion
export { buildGroupDisplayTitle as n, resolveGroupSessionKey as r, buildGroupDisplayName as t };