Files
openclaw/src/sessions/session-chat-type.ts
2026-04-03 20:39:36 -07:00

63 lines
1.9 KiB
TypeScript

import { getBundledChannelContractSurfaces } from "../channels/plugins/contract-surfaces.js";
import { parseAgentSessionKey } from "./session-key-utils.js";
export type SessionKeyChatType = "direct" | "group" | "channel" | "unknown";
type LegacySessionChatTypeSurface = {
deriveLegacySessionChatType?: (sessionKey: string) => "direct" | "group" | "channel" | undefined;
};
function listLegacySessionChatTypeSurfaces(): LegacySessionChatTypeSurface[] {
return getBundledChannelContractSurfaces() as LegacySessionChatTypeSurface[];
}
function deriveBuiltInLegacySessionChatType(
scopedSessionKey: string,
): SessionKeyChatType | undefined {
if (/^group:[^:]+$/.test(scopedSessionKey)) {
return "group";
}
if (/^[0-9]+(?:-[0-9]+)*@g\.us$/.test(scopedSessionKey)) {
return "group";
}
if (/^whatsapp:(?!.*:group:).+@g\.us$/.test(scopedSessionKey)) {
return "group";
}
if (/^discord:(?:[^:]+:)?guild-[^:]+:channel-[^:]+$/.test(scopedSessionKey)) {
return "channel";
}
return undefined;
}
/**
* Best-effort chat-type extraction from session keys across canonical and legacy formats.
*/
export function deriveSessionChatType(sessionKey: string | undefined | null): SessionKeyChatType {
const raw = (sessionKey ?? "").trim().toLowerCase();
if (!raw) {
return "unknown";
}
const scoped = parseAgentSessionKey(raw)?.rest ?? raw;
const tokens = new Set(scoped.split(":").filter(Boolean));
if (tokens.has("group")) {
return "group";
}
if (tokens.has("channel")) {
return "channel";
}
if (tokens.has("direct") || tokens.has("dm")) {
return "direct";
}
const builtInLegacy = deriveBuiltInLegacySessionChatType(scoped);
if (builtInLegacy) {
return builtInLegacy;
}
for (const surface of listLegacySessionChatTypeSurfaces()) {
const derived = surface.deriveLegacySessionChatType?.(scoped);
if (derived) {
return derived;
}
}
return "unknown";
}