






















@@ -0,0 +1,159 @@
1+import {
2+normalizeLowercaseStringOrEmpty,
3+normalizeOptionalString,
4+normalizeOptionalStringifiedId,
5+} from "openclaw/plugin-sdk/text-runtime";
6+import { resolveDiscordCurrentConversationIdentity } from "./conversation-identity.js";
7+import { normalizeDiscordMessagingTarget } from "./normalize.js";
8+import { parseDiscordTarget } from "./target-parsing.js";
9+10+export function resolveDiscordAttachedOutboundTarget(params: {
11+to: string;
12+threadId?: string | number | null;
13+}): string {
14+if (params.threadId == null) {
15+return params.to;
16+}
17+const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
18+return threadId ? `channel:${threadId}` : params.to;
19+}
20+21+export function buildDiscordCrossContextPresentation(params: {
22+originLabel: string;
23+message: string;
24+}) {
25+const trimmed = params.message.trim();
26+return {
27+tone: "neutral" as const,
28+blocks: [
29+ ...(trimmed
30+ ? ([{ type: "text" as const, text: params.message }, { type: "divider" as const }] as const)
31+ : []),
32+{ type: "context" as const, text: `From ${params.originLabel}` },
33+],
34+};
35+}
36+37+export function normalizeDiscordAcpConversationId(conversationId: string) {
38+const normalized = conversationId.trim();
39+return normalized ? { conversationId: normalized } : null;
40+}
41+42+export function matchDiscordAcpConversation(params: {
43+bindingConversationId: string;
44+conversationId: string;
45+parentConversationId?: string;
46+}) {
47+if (params.bindingConversationId === params.conversationId) {
48+return { conversationId: params.conversationId, matchPriority: 2 };
49+}
50+if (
51+params.parentConversationId &&
52+params.parentConversationId !== params.conversationId &&
53+params.bindingConversationId === params.parentConversationId
54+) {
55+return {
56+conversationId: params.parentConversationId,
57+matchPriority: 1,
58+};
59+}
60+return null;
61+}
62+63+function resolveDiscordConversationIdFromTargets(
64+targets: Array<string | undefined>,
65+): string | undefined {
66+for (const raw of targets) {
67+const trimmed = raw?.trim();
68+if (!trimmed) {
69+continue;
70+}
71+try {
72+const target = parseDiscordTarget(trimmed, { defaultKind: "channel" });
73+if (target?.normalized) {
74+return target.normalized;
75+}
76+} catch {
77+const mentionMatch = trimmed.match(/^<#(\d+)>$/);
78+if (mentionMatch?.[1]) {
79+return `channel:${mentionMatch[1]}`;
80+}
81+if (/^\d{6,}$/.test(trimmed)) {
82+return normalizeDiscordMessagingTarget(trimmed);
83+}
84+}
85+}
86+return undefined;
87+}
88+89+function parseDiscordParentChannelFromSessionKey(raw: unknown): string | undefined {
90+const sessionKey = normalizeLowercaseStringOrEmpty(raw);
91+if (!sessionKey) {
92+return undefined;
93+}
94+const match = sessionKey.match(/(?:^|:)channel:([^:]+)$/);
95+return match?.[1] ? `channel:${match[1]}` : undefined;
96+}
97+98+export function resolveDiscordCommandConversation(params: {
99+threadId?: string;
100+threadParentId?: string;
101+parentSessionKey?: string;
102+from?: string;
103+chatType?: string;
104+originatingTo?: string;
105+commandTo?: string;
106+fallbackTo?: string;
107+}) {
108+const targets = [params.originatingTo, params.commandTo, params.fallbackTo];
109+if (params.threadId) {
110+const parentConversationId =
111+normalizeDiscordMessagingTarget(normalizeOptionalString(params.threadParentId) ?? "") ||
112+parseDiscordParentChannelFromSessionKey(params.parentSessionKey) ||
113+resolveDiscordConversationIdFromTargets(targets);
114+return {
115+conversationId: params.threadId,
116+ ...(parentConversationId && parentConversationId !== params.threadId
117+ ? { parentConversationId }
118+ : {}),
119+};
120+}
121+const conversationId = resolveDiscordCurrentConversationIdentity({
122+from: params.from,
123+chatType: params.chatType,
124+originatingTo: params.originatingTo,
125+commandTo: params.commandTo,
126+fallbackTo: params.fallbackTo,
127+});
128+return conversationId ? { conversationId } : null;
129+}
130+131+export function resolveDiscordInboundConversation(params: {
132+from?: string;
133+to?: string;
134+conversationId?: string;
135+isGroup: boolean;
136+}) {
137+const conversationId = resolveDiscordCurrentConversationIdentity({
138+from: params.from,
139+chatType: params.isGroup ? "group" : "direct",
140+originatingTo: params.to,
141+fallbackTo: params.conversationId,
142+});
143+return conversationId ? { conversationId } : null;
144+}
145+146+export function parseDiscordExplicitTarget(raw: string) {
147+try {
148+const target = parseDiscordTarget(raw, { defaultKind: "channel" });
149+if (!target) {
150+return null;
151+}
152+return {
153+to: target.normalized,
154+chatType: target.kind === "user" ? ("direct" as const) : ("channel" as const),
155+};
156+} catch {
157+return null;
158+}
159+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。