diff --git a/extensions/zalouser/src/channel.ts b/extensions/zalouser/src/channel.ts index f0170af4aa1..b86b3ef8156 100644 --- a/extensions/zalouser/src/channel.ts +++ b/extensions/zalouser/src/channel.ts @@ -33,6 +33,7 @@ import { probeZalouser } from "./probe.js"; import { writeQrDataUrlToTempFile } from "./qr-temp-file.js"; import { getZalouserRuntime } from "./runtime.js"; import { sendMessageZalouser, sendReactionZalouser } from "./send.js"; +import { resolveZalouserOutboundSessionRoute } from "./session-route.js"; import { zalouserSetupAdapter } from "./setup-core.js"; import { zalouserSetupWizard } from "./setup-surface.js"; import { createZalouserPluginBase } from "./shared.js"; @@ -312,6 +313,7 @@ export const zalouserPlugin: ChannelPlugin = { actions: zalouserMessageActions, messaging: { normalizeTarget: (raw) => normalizePrefixedTarget(raw), + resolveOutboundSessionRoute: (params) => resolveZalouserOutboundSessionRoute(params), targetResolver: { looksLikeId: (raw) => { const normalized = normalizePrefixedTarget(raw); diff --git a/extensions/zalouser/src/session-route.ts b/extensions/zalouser/src/session-route.ts new file mode 100644 index 00000000000..c6a1761818d --- /dev/null +++ b/extensions/zalouser/src/session-route.ts @@ -0,0 +1,70 @@ +import { + buildChannelOutboundSessionRoute, + type ChannelOutboundSessionRouteParams, +} from "openclaw/plugin-sdk/core"; + +function stripZalouserTargetPrefix(raw: string): string { + return raw + .trim() + .replace(/^(zalouser|zlu):/i, "") + .trim(); +} + +function normalizePrefixedTarget(raw: string): string | undefined { + const trimmed = stripZalouserTargetPrefix(raw); + if (!trimmed) { + return undefined; + } + + const lower = trimmed.toLowerCase(); + if (lower.startsWith("group:")) { + const id = trimmed.slice("group:".length).trim(); + return id ? `group:${id}` : undefined; + } + if (lower.startsWith("g:")) { + const id = trimmed.slice("g:".length).trim(); + return id ? `group:${id}` : undefined; + } + if (lower.startsWith("user:")) { + const id = trimmed.slice("user:".length).trim(); + return id ? `user:${id}` : undefined; + } + if (lower.startsWith("dm:")) { + const id = trimmed.slice("dm:".length).trim(); + return id ? `user:${id}` : undefined; + } + if (lower.startsWith("u:")) { + const id = trimmed.slice("u:".length).trim(); + return id ? `user:${id}` : undefined; + } + if (/^g-\S+$/i.test(trimmed)) { + return `group:${trimmed}`; + } + if (/^u-\S+$/i.test(trimmed)) { + return `user:${trimmed}`; + } + + return trimmed; +} + +export function resolveZalouserOutboundSessionRoute(params: ChannelOutboundSessionRouteParams) { + const normalized = normalizePrefixedTarget(params.target); + if (!normalized) { + return null; + } + const isGroup = normalized.toLowerCase().startsWith("group:"); + const peerId = normalized.replace(/^(group|user):/i, "").trim(); + return buildChannelOutboundSessionRoute({ + cfg: params.cfg, + agentId: params.agentId, + channel: "zalouser", + accountId: params.accountId, + peer: { + kind: isGroup ? "group" : "direct", + id: peerId, + }, + chatType: isGroup ? "group" : "direct", + from: isGroup ? `zalouser:group:${peerId}` : `zalouser:${peerId}`, + to: `zalouser:${peerId}`, + }); +}