diff --git a/extensions/feishu/src/channel.ts b/extensions/feishu/src/channel.ts index 649c51a7ad9..d56c80bb482 100644 --- a/extensions/feishu/src/channel.ts +++ b/extensions/feishu/src/channel.ts @@ -34,6 +34,7 @@ import { parseFeishuConversationId } from "./conversation-id.js"; import { listFeishuDirectoryPeers, listFeishuDirectoryGroups } from "./directory.static.js"; import { resolveFeishuGroupToolPolicy } from "./policy.js"; import { getFeishuRuntime } from "./runtime.js"; +import { resolveFeishuOutboundSessionRoute } from "./session-route.js"; import { feishuSetupAdapter } from "./setup-core.js"; import { feishuSetupWizard } from "./setup-surface.js"; import { normalizeFeishuTarget, looksLikeFeishuId, formatFeishuTarget } from "./targets.js"; @@ -871,6 +872,7 @@ export const feishuPlugin: ChannelPlugin = { setupWizard: feishuSetupWizard, messaging: { normalizeTarget: (raw) => normalizeFeishuTarget(raw) ?? undefined, + resolveOutboundSessionRoute: (params) => resolveFeishuOutboundSessionRoute(params), targetResolver: { looksLikeId: looksLikeFeishuId, hint: "", diff --git a/extensions/feishu/src/session-route.ts b/extensions/feishu/src/session-route.ts new file mode 100644 index 00000000000..5f8884a33ec --- /dev/null +++ b/extensions/feishu/src/session-route.ts @@ -0,0 +1,47 @@ +import { + buildChannelOutboundSessionRoute, + stripChannelTargetPrefix, + type ChannelOutboundSessionRouteParams, +} from "openclaw/plugin-sdk/core"; + +export function resolveFeishuOutboundSessionRoute(params: ChannelOutboundSessionRouteParams) { + let trimmed = stripChannelTargetPrefix(params.target, "feishu", "lark"); + if (!trimmed) { + return null; + } + + const lower = trimmed.toLowerCase(); + let isGroup = false; + let typeExplicit = false; + + if (lower.startsWith("group:") || lower.startsWith("chat:") || lower.startsWith("channel:")) { + trimmed = trimmed.replace(/^(group|chat|channel):/i, "").trim(); + isGroup = true; + typeExplicit = true; + } else if (lower.startsWith("user:") || lower.startsWith("dm:")) { + trimmed = trimmed.replace(/^(user|dm):/i, "").trim(); + isGroup = false; + typeExplicit = true; + } + + if (!typeExplicit) { + const idLower = trimmed.toLowerCase(); + if (idLower.startsWith("ou_") || idLower.startsWith("on_")) { + isGroup = false; + } + } + + return buildChannelOutboundSessionRoute({ + cfg: params.cfg, + agentId: params.agentId, + channel: "feishu", + accountId: params.accountId, + peer: { + kind: isGroup ? "group" : "direct", + id: trimmed, + }, + chatType: isGroup ? "group" : "direct", + from: isGroup ? `feishu:group:${trimmed}` : `feishu:${trimmed}`, + to: trimmed, + }); +}