diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed3fb09f46..1b2b5da4df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Feishu/Lark private DM routing: treat inbound `chat_type: "private"` as direct-message context for pairing/mention-forward/reaction synthetic handling so Lark private chats behave like Feishu p2p DMs. (#31400) Thanks @stakeswky. - Sandbox/workspace mount permissions: make primary `/workspace` bind mounts read-only whenever `workspaceAccess` is not `rw` (including `none`) across both core sandbox container and sandbox browser create flows. (#32227) Thanks @guanyu-zhang. - Signal/message actions: allow `react` to fall back to `toolContext.currentMessageId` when `messageId` is omitted, matching Telegram behavior and unblocking agent-initiated reactions on inbound turns. (#32217) Thanks @dunamismax. - Gateway/OpenAI chat completions: honor `x-openclaw-message-channel` when building `agentCommand` input for `/v1/chat/completions`, preserving caller channel identity instead of forcing `webchat`. (#30462) Thanks @bmendonca3. diff --git a/extensions/feishu/src/bot.checkBotMentioned.test.ts b/extensions/feishu/src/bot.checkBotMentioned.test.ts index 3036677e471..8b45fc4c2c3 100644 --- a/extensions/feishu/src/bot.checkBotMentioned.test.ts +++ b/extensions/feishu/src/bot.checkBotMentioned.test.ts @@ -3,7 +3,7 @@ import { parseFeishuMessageEvent } from "./bot.js"; // Helper to build a minimal FeishuMessageEvent for testing function makeEvent( - chatType: "p2p" | "group", + chatType: "p2p" | "group" | "private", mentions?: Array<{ key: string; name: string; id: { open_id?: string } }>, text = "hello", ) { diff --git a/extensions/feishu/src/bot.ts b/extensions/feishu/src/bot.ts index f6e4e488735..d50eeb7d80e 100644 --- a/extensions/feishu/src/bot.ts +++ b/extensions/feishu/src/bot.ts @@ -165,7 +165,7 @@ export type FeishuMessageEvent = { root_id?: string; parent_id?: string; chat_id: string; - chat_type: "p2p" | "group"; + chat_type: "p2p" | "group" | "private"; message_type: string; content: string; create_time?: string; @@ -709,6 +709,7 @@ export async function handleFeishuMessage(params: { let ctx = parseFeishuMessageEvent(event, botOpenId); const isGroup = ctx.chatType === "group"; + const isDirect = !isGroup; const senderUserId = event.sender.sender_id.user_id?.trim() || undefined; // Handle merge_forward messages: fetch full message via API then expand sub-messages @@ -895,7 +896,7 @@ export async function handleFeishuMessage(params: { senderName: ctx.senderName, }).allowed; - if (!isGroup && dmPolicy !== "open" && !dmAllowed) { + if (isDirect && dmPolicy !== "open" && !dmAllowed) { if (dmPolicy === "pairing") { const { code, created } = await pairing.upsertPairingRequest({ id: ctx.senderOpenId, diff --git a/extensions/feishu/src/mention.ts b/extensions/feishu/src/mention.ts index 50c6fae5ed2..9c0fd96e35f 100644 --- a/extensions/feishu/src/mention.ts +++ b/extensions/feishu/src/mention.ts @@ -53,7 +53,7 @@ export function isMentionForwardRequest(event: FeishuMessageEvent, botOpenId?: s return false; } - const isDirectMessage = event.message.chat_type === "p2p"; + const isDirectMessage = event.message.chat_type !== "group"; const hasOtherMention = mentions.some((m) => m.id.open_id !== botOpenId); if (isDirectMessage) { diff --git a/extensions/feishu/src/monitor.account.ts b/extensions/feishu/src/monitor.account.ts index 77dbf44dea9..e23fd8269da 100644 --- a/extensions/feishu/src/monitor.account.ts +++ b/extensions/feishu/src/monitor.account.ts @@ -17,7 +17,7 @@ const FEISHU_REACTION_VERIFY_TIMEOUT_MS = 1_500; export type FeishuReactionCreatedEvent = { message_id: string; chat_id?: string; - chat_type?: "p2p" | "group"; + chat_type?: "p2p" | "group" | "private"; reaction_type?: { emoji_type?: string }; operator_type?: string; user_id?: { open_id?: string }; @@ -93,7 +93,8 @@ export async function resolveReactionSyntheticEvent( const syntheticChatIdRaw = event.chat_id ?? reactedMsg.chatId; const syntheticChatId = syntheticChatIdRaw?.trim() ? syntheticChatIdRaw : `p2p:${senderId}`; - const syntheticChatType: "p2p" | "group" = event.chat_type ?? "p2p"; + const syntheticChatType: "p2p" | "group" | "private" = + event.chat_type === "group" ? "group" : "p2p"; return { sender: { sender_id: { open_id: senderId }, diff --git a/extensions/feishu/src/types.ts b/extensions/feishu/src/types.ts index 4dbf2c13069..aae6f6feae7 100644 --- a/extensions/feishu/src/types.ts +++ b/extensions/feishu/src/types.ts @@ -36,7 +36,7 @@ export type FeishuMessageContext = { senderId: string; senderOpenId: string; senderName?: string; - chatType: "p2p" | "group"; + chatType: "p2p" | "group" | "private"; mentionedBot: boolean; rootId?: string; parentId?: string;