mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 04:15:48 -06:00
177 lines
5.2 KiB
TypeScript
177 lines
5.2 KiB
TypeScript
// Discord plugin module implements channel.conversation behavior.
|
|
import {
|
|
normalizeLowercaseStringOrEmpty,
|
|
normalizeOptionalStringifiedId,
|
|
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
import { resolveDiscordCurrentConversationIdentity } from "./conversation-identity.js";
|
|
import { normalizeDiscordMessagingTarget } from "./normalize.js";
|
|
import { parseDiscordTarget } from "./target-parsing.js";
|
|
|
|
export function resolveDiscordAttachedOutboundTarget(params: {
|
|
to: string;
|
|
threadId?: string | number | null;
|
|
}): string {
|
|
if (params.threadId == null) {
|
|
return params.to;
|
|
}
|
|
const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
|
|
return threadId ? `channel:${threadId}` : params.to;
|
|
}
|
|
|
|
export function buildDiscordCrossContextPresentation(params: {
|
|
originLabel: string;
|
|
message: string;
|
|
}) {
|
|
const trimmed = params.message.trim();
|
|
return {
|
|
tone: "neutral" as const,
|
|
blocks: [
|
|
...(trimmed
|
|
? ([{ type: "text" as const, text: params.message }, { type: "divider" as const }] as const)
|
|
: []),
|
|
{ type: "context" as const, text: `From ${params.originLabel}` },
|
|
],
|
|
};
|
|
}
|
|
|
|
export function normalizeDiscordAcpConversationId(conversationId: string) {
|
|
const normalized = conversationId.trim();
|
|
return normalized ? { conversationId: normalized } : null;
|
|
}
|
|
|
|
export function matchDiscordAcpConversation(params: {
|
|
bindingConversationId: string;
|
|
conversationId: string;
|
|
parentConversationId?: string;
|
|
}) {
|
|
if (params.bindingConversationId === params.conversationId) {
|
|
return { conversationId: params.conversationId, matchPriority: 2 };
|
|
}
|
|
if (
|
|
params.parentConversationId &&
|
|
params.parentConversationId !== params.conversationId &&
|
|
params.bindingConversationId === params.parentConversationId
|
|
) {
|
|
return {
|
|
conversationId: params.parentConversationId,
|
|
matchPriority: 1,
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resolveDiscordConversationIdFromTargets(
|
|
targets: Array<string | undefined>,
|
|
): string | undefined {
|
|
for (const raw of targets) {
|
|
const trimmed = raw?.trim();
|
|
if (!trimmed) {
|
|
continue;
|
|
}
|
|
try {
|
|
const target = parseDiscordTarget(trimmed, { defaultKind: "channel" });
|
|
if (target?.normalized) {
|
|
return target.normalized;
|
|
}
|
|
} catch {
|
|
const mentionMatch = trimmed.match(/^<#(\d+)>$/);
|
|
if (mentionMatch?.[1]) {
|
|
return `channel:${mentionMatch[1]}`;
|
|
}
|
|
if (/^\d{6,}$/.test(trimmed)) {
|
|
return normalizeDiscordMessagingTarget(trimmed);
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function parseDiscordParentChannelFromSessionKey(raw: unknown): string | undefined {
|
|
const sessionKey = normalizeLowercaseStringOrEmpty(raw);
|
|
if (!sessionKey) {
|
|
return undefined;
|
|
}
|
|
const match = sessionKey.match(/(?:^|:)channel:([^:]+)$/);
|
|
return match?.[1] ? `channel:${match[1]}` : undefined;
|
|
}
|
|
|
|
export function resolveDiscordCommandConversation(params: {
|
|
threadId?: string | number;
|
|
threadParentId?: string;
|
|
parentSessionKey?: string;
|
|
from?: string;
|
|
chatType?: string;
|
|
originatingTo?: string;
|
|
commandTo?: string;
|
|
fallbackTo?: string;
|
|
}) {
|
|
const threadConversation = resolveDiscordThreadConversationRef(params);
|
|
if (threadConversation) {
|
|
return threadConversation;
|
|
}
|
|
const conversationId = resolveDiscordCurrentConversationIdentity({
|
|
from: params.from,
|
|
chatType: params.chatType,
|
|
originatingTo: params.originatingTo,
|
|
commandTo: params.commandTo,
|
|
fallbackTo: params.fallbackTo,
|
|
});
|
|
return conversationId ? { conversationId } : null;
|
|
}
|
|
|
|
function resolveDiscordThreadConversationRef(params: {
|
|
threadId?: string | number | null;
|
|
threadParentId?: string | number | null;
|
|
parentSessionKey?: string | null;
|
|
originatingTo?: string;
|
|
to?: string;
|
|
commandTo?: string;
|
|
fallbackTo?: string;
|
|
conversationId?: string;
|
|
}) {
|
|
const threadId = normalizeOptionalStringifiedId(params.threadId);
|
|
if (!threadId) {
|
|
return null;
|
|
}
|
|
const targets = [
|
|
params.originatingTo ?? params.to,
|
|
params.commandTo,
|
|
params.fallbackTo ?? params.conversationId,
|
|
];
|
|
const parentConversationId =
|
|
normalizeDiscordMessagingTarget(normalizeOptionalStringifiedId(params.threadParentId) ?? "") ||
|
|
parseDiscordParentChannelFromSessionKey(params.parentSessionKey) ||
|
|
resolveDiscordConversationIdFromTargets(targets);
|
|
|
|
return {
|
|
conversationId: threadId,
|
|
...(parentConversationId && parentConversationId !== threadId ? { parentConversationId } : {}),
|
|
};
|
|
}
|
|
|
|
export function resolveDiscordInboundConversation(params: {
|
|
from?: string;
|
|
to?: string;
|
|
conversationId?: string;
|
|
threadId?: string | number;
|
|
threadParentId?: string | number;
|
|
isGroup: boolean;
|
|
}) {
|
|
const threadConversation = resolveDiscordThreadConversationRef({
|
|
to: params.to,
|
|
conversationId: params.conversationId,
|
|
threadId: params.threadId,
|
|
threadParentId: params.threadParentId,
|
|
});
|
|
if (threadConversation) {
|
|
return threadConversation;
|
|
}
|
|
const conversationId = resolveDiscordCurrentConversationIdentity({
|
|
from: params.from,
|
|
chatType: params.isGroup ? "group" : "direct",
|
|
originatingTo: params.to,
|
|
fallbackTo: params.conversationId,
|
|
});
|
|
return conversationId ? { conversationId } : null;
|
|
}
|