@openclaw/feishu 2026.5.7 → 2026.5.10-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +3 -2
- package/dist/{channel-BegH3cJm.js → channel-DCSECj4a.js} +63 -9
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-DYsXcD36.js → channel.runtime-BlDkd6xR.js} +35 -18
- package/dist/{monitor-BVR-x39Q.js → monitor-BnbCJWIU.js} +1 -1
- package/dist/{monitor.account-CUZxYkjE.js → monitor.account-88yMtLAU.js} +178 -129
- package/dist/policy-DrLgxWF_.js +181 -0
- package/dist/runtime-api.js +1 -1
- package/dist/{send-DowxxbpH.js → send-DKHEQrzH.js} +48 -61
- package/dist/{card-interaction-BfRLgvw_.js → send-result-BVFTskB_.js} +45 -1
- package/dist/setup-api.js +1 -1
- package/package.json +6 -6
- package/dist/policy-D6c-wMPl.js +0 -118
|
@@ -2,17 +2,18 @@ import { t as buildFeishuConversationId } from "./conversation-id-DWS3Ep2A.js";
|
|
|
2
2
|
import { i as resolveReceiveIdType } from "./targets-JMFJRKSe.js";
|
|
3
3
|
import { n as createFeishuThreadBindingManager } from "./thread-bindings-BmS6TLes.js";
|
|
4
4
|
import { _ as buildFeishuCommentTarget, f as isRecord$3, h as readString$2, l as encodeQuery, m as parseCommentContentElements, p as normalizeString, s as resolveFeishuRuntimeAccount, u as extractReplyText, v as normalizeCommentFileType } from "./accounts-Ba3-WP1z.js";
|
|
5
|
-
import {
|
|
6
|
-
import { i as
|
|
5
|
+
import { c as decodeFeishuCardAction, o as buildFeishuCardActionTextFallback, s as createFeishuCardInteractionEnvelope } from "./send-result-BVFTskB_.js";
|
|
6
|
+
import { a as resolveFeishuGroupSenderActivationIngressAccess, i as resolveFeishuGroupConversationIngressAccess, n as resolveFeishuDmIngressAccess, r as resolveFeishuGroupConfig, s as resolveFeishuReplyPolicy, t as hasExplicitFeishuGroupConfig } from "./policy-DrLgxWF_.js";
|
|
7
7
|
import { t as getFeishuRuntime } from "./runtime-CG0DuRCy.js";
|
|
8
8
|
import { a as getFeishuUserAgent, i as createFeishuWSClient, n as createEventDispatcher, r as createFeishuClient } from "./client-DBVoQL5w.js";
|
|
9
9
|
import { c as getChatInfo, i as createCommentTypingReactionLifecycle, t as deliverCommentThreadText } from "./drive-C5eJLJr7.js";
|
|
10
|
-
import { buildAgentMediaPayload, createReplyPrefixContext, evaluateSupplementalContextVisibility,
|
|
11
|
-
import { _ as
|
|
10
|
+
import { buildAgentMediaPayload, createReplyPrefixContext, evaluateSupplementalContextVisibility, loadSessionStore, normalizeAgentId as normalizeAgentId$1, resolveChannelContextVisibilityMode, resolveSessionStoreEntry } from "./runtime-api.js";
|
|
11
|
+
import { _ as normalizeFeishuExternalKey, a as sendCardFeishu, c as sendStructuredCardFeishu, d as isFeishuBroadcastMention, f as isMentionForwardRequest, g as shouldSuppressFeishuTextForVoiceMedia, h as sendMediaFeishu, i as resolveFeishuCardTemplate, l as parsePostContent, m as downloadMessageResourceFeishu, n as getMessageFeishu, p as isFeishuGroupChatType, r as listFeishuThreadMessages, s as sendMessageFeishu, u as extractMentionTargets } from "./send-DKHEQrzH.js";
|
|
12
12
|
import { i as waitForAbortableDelay, r as raceWithTimeoutAndAbort } from "./probe-BNzzU_uR.js";
|
|
13
13
|
import { a as feishuWebhookRateLimiter, c as wsClients, i as botOpenIds, l as fetchBotIdentityForMonitor, n as FEISHU_WEBHOOK_MAX_BODY_BYTES, o as httpServers, r as botNames, s as recordWebhookStatus, t as FEISHU_WEBHOOK_BODY_TIMEOUT_MS } from "./monitor.state-DYM02ipp.js";
|
|
14
14
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-runtime";
|
|
15
15
|
import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
|
|
16
|
+
import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-message";
|
|
16
17
|
import { createChannelPairingController, createChannelPairingController as createChannelPairingController$1 } from "openclaw/plugin-sdk/channel-pairing";
|
|
17
18
|
import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/outbound-runtime";
|
|
18
19
|
import fs from "node:fs";
|
|
@@ -20,16 +21,17 @@ import os from "node:os";
|
|
|
20
21
|
import path from "node:path";
|
|
21
22
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
22
23
|
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
23
|
-
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
|
24
24
|
import { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
25
25
|
import { applyBasicWebhookRequestGuards } from "openclaw/plugin-sdk/webhook-ingress";
|
|
26
26
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
27
27
|
import { resolveSendableOutboundReplyParts, resolveTextChunksWithFallback, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
|
|
28
|
+
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
28
29
|
import * as crypto$1 from "node:crypto";
|
|
29
30
|
import crypto from "node:crypto";
|
|
31
|
+
import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
|
|
30
32
|
import { DEFAULT_GROUP_HISTORY_LIMIT, buildPendingHistoryContextFromMap, clearHistoryEntriesIfEnabled, recordPendingHistoryEntryIfEnabled } from "openclaw/plugin-sdk/reply-history";
|
|
31
33
|
import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
32
|
-
import {
|
|
34
|
+
import { formatReasoningMessage } from "openclaw/plugin-sdk/agent-runtime";
|
|
33
35
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
34
36
|
import { formatChannelProgressDraftLineForEntry, isChannelProgressDraftWorkToolName } from "openclaw/plugin-sdk/channel-streaming";
|
|
35
37
|
import * as http from "node:http";
|
|
@@ -550,7 +552,14 @@ function resolveFeishuMessageDedupeKey(event) {
|
|
|
550
552
|
* This creates a unique agent instance with its own workspace for each DM user.
|
|
551
553
|
*/
|
|
552
554
|
async function maybeCreateDynamicAgent(params) {
|
|
553
|
-
const { cfg, runtime, senderOpenId, dynamicCfg, log } = params;
|
|
555
|
+
const { cfg, runtime, senderOpenId, dynamicCfg, configWritesAllowed, log } = params;
|
|
556
|
+
if (!configWritesAllowed) {
|
|
557
|
+
log(`feishu: config writes disabled, not creating agent for ${senderOpenId}`);
|
|
558
|
+
return {
|
|
559
|
+
created: false,
|
|
560
|
+
updatedCfg: cfg
|
|
561
|
+
};
|
|
562
|
+
}
|
|
554
563
|
const existingBindings = cfg.bindings ?? [];
|
|
555
564
|
if (existingBindings.some((b) => b.match?.channel === "feishu" && b.match?.peer?.kind === "direct" && b.match?.peer?.id === senderOpenId)) return {
|
|
556
565
|
created: false,
|
|
@@ -639,17 +648,30 @@ function resolveUserPath(p) {
|
|
|
639
648
|
return p;
|
|
640
649
|
}
|
|
641
650
|
//#endregion
|
|
651
|
+
//#region extensions/feishu/src/agent-config.ts
|
|
652
|
+
const DEFAULT_AGENT_ID = "main";
|
|
653
|
+
function normalizeAgentId(value) {
|
|
654
|
+
return (value ?? "").trim().toLowerCase() || DEFAULT_AGENT_ID;
|
|
655
|
+
}
|
|
656
|
+
function resolveFeishuConfigReasoningDefault(cfg, agentId) {
|
|
657
|
+
const id = normalizeAgentId(agentId);
|
|
658
|
+
return cfg.agents?.list?.find((entry) => normalizeAgentId(entry?.id) === id)?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault ?? "off";
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
642
661
|
//#region extensions/feishu/src/reasoning-preview.ts
|
|
643
662
|
function resolveFeishuReasoningPreviewEnabled(params) {
|
|
644
|
-
|
|
663
|
+
const configDefault = resolveFeishuConfigReasoningDefault(params.cfg, params.agentId);
|
|
664
|
+
if (!params.sessionKey) return configDefault === "stream";
|
|
645
665
|
try {
|
|
646
|
-
|
|
666
|
+
const level = resolveSessionStoreEntry({
|
|
647
667
|
store: loadSessionStore(params.storePath, { skipCache: true }),
|
|
648
668
|
sessionKey: params.sessionKey
|
|
649
|
-
}).existing?.reasoningLevel
|
|
669
|
+
}).existing?.reasoningLevel;
|
|
670
|
+
if (level === "on" || level === "stream" || level === "off") return level === "stream";
|
|
650
671
|
} catch {
|
|
651
672
|
return false;
|
|
652
673
|
}
|
|
674
|
+
return configDefault === "stream";
|
|
653
675
|
}
|
|
654
676
|
//#endregion
|
|
655
677
|
//#region extensions/feishu/src/streaming-card.ts
|
|
@@ -1179,7 +1201,7 @@ function resolveCardNote(agentId, identity, prefixCtx) {
|
|
|
1179
1201
|
}
|
|
1180
1202
|
function createFeishuReplyDispatcher(params) {
|
|
1181
1203
|
const core = getFeishuRuntime();
|
|
1182
|
-
const { cfg, agentId, chatId, replyToMessageId, skipReplyToInMessages, replyInThread, threadReply, rootId,
|
|
1204
|
+
const { cfg, agentId, chatId, replyToMessageId, skipReplyToInMessages, replyInThread, threadReply, rootId, accountId, identity } = params;
|
|
1183
1205
|
const sendReplyToMessageId = skipReplyToInMessages ? void 0 : replyToMessageId;
|
|
1184
1206
|
const effectiveReplyInThread = threadReply === true ? true : replyInThread;
|
|
1185
1207
|
const account = resolveFeishuRuntimeAccount({
|
|
@@ -1191,7 +1213,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1191
1213
|
agentId
|
|
1192
1214
|
});
|
|
1193
1215
|
let typingState = null;
|
|
1194
|
-
const { typingCallbacks } =
|
|
1216
|
+
const { typingCallbacks } = createChannelMessageReplyPipeline({
|
|
1195
1217
|
cfg,
|
|
1196
1218
|
agentId,
|
|
1197
1219
|
channel: "feishu",
|
|
@@ -1329,8 +1351,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1329
1351
|
await partialUpdateQueue;
|
|
1330
1352
|
if (streaming?.isActive()) {
|
|
1331
1353
|
statusLine = "";
|
|
1332
|
-
|
|
1333
|
-
if (mentionTargets?.length) text = buildMentionedCardContent(mentionTargets, text);
|
|
1354
|
+
const text = buildCombinedStreamText(reasoningText, streamText);
|
|
1334
1355
|
const finalNote = resolveCardNote(agentId, identity, prefixContext.prefixContext);
|
|
1335
1356
|
await streaming.close(text, { note: finalNote });
|
|
1336
1357
|
if (streamText) {
|
|
@@ -1386,14 +1407,13 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1386
1407
|
text: options.fallbackText,
|
|
1387
1408
|
useCard: false,
|
|
1388
1409
|
infoKind: "final",
|
|
1389
|
-
sendChunk: async ({ chunk
|
|
1410
|
+
sendChunk: async ({ chunk }) => {
|
|
1390
1411
|
await sendMessageFeishu({
|
|
1391
1412
|
cfg,
|
|
1392
1413
|
to: chatId,
|
|
1393
1414
|
text: chunk,
|
|
1394
1415
|
replyToMessageId: sendReplyToMessageId,
|
|
1395
1416
|
replyInThread: effectiveReplyInThread,
|
|
1396
|
-
mentions: isFirst ? mentionTargets : void 0,
|
|
1397
1417
|
accountId
|
|
1398
1418
|
});
|
|
1399
1419
|
}
|
|
@@ -1407,14 +1427,13 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1407
1427
|
text: fallbackText,
|
|
1408
1428
|
useCard: false,
|
|
1409
1429
|
infoKind: "final",
|
|
1410
|
-
sendChunk: async ({ chunk
|
|
1430
|
+
sendChunk: async ({ chunk }) => {
|
|
1411
1431
|
await sendMessageFeishu({
|
|
1412
1432
|
cfg,
|
|
1413
1433
|
to: chatId,
|
|
1414
1434
|
text: chunk,
|
|
1415
1435
|
replyToMessageId: sendReplyToMessageId,
|
|
1416
1436
|
replyInThread: effectiveReplyInThread,
|
|
1417
|
-
mentions: isFirst ? mentionTargets : void 0,
|
|
1418
1437
|
accountId
|
|
1419
1438
|
});
|
|
1420
1439
|
}
|
|
@@ -1434,7 +1453,11 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1434
1453
|
await typingCallbacks?.onReplyStart?.();
|
|
1435
1454
|
},
|
|
1436
1455
|
deliver: async (payload, info) => {
|
|
1437
|
-
const
|
|
1456
|
+
const payloadText = payload.isReasoning && payload.text ? formatReasoningMessage(payload.text) : payload.text;
|
|
1457
|
+
const reply = resolveSendableOutboundReplyParts({
|
|
1458
|
+
...payload,
|
|
1459
|
+
text: payloadText
|
|
1460
|
+
});
|
|
1438
1461
|
const text = reply.text;
|
|
1439
1462
|
const hasText = reply.hasText;
|
|
1440
1463
|
const hasMedia = reply.hasMedia;
|
|
@@ -1478,14 +1501,13 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1478
1501
|
text,
|
|
1479
1502
|
useCard: true,
|
|
1480
1503
|
infoKind: info?.kind,
|
|
1481
|
-
sendChunk: async ({ chunk
|
|
1504
|
+
sendChunk: async ({ chunk }) => {
|
|
1482
1505
|
await sendStructuredCardFeishu({
|
|
1483
1506
|
cfg,
|
|
1484
1507
|
to: chatId,
|
|
1485
1508
|
text: chunk,
|
|
1486
1509
|
replyToMessageId: sendReplyToMessageId,
|
|
1487
1510
|
replyInThread: effectiveReplyInThread,
|
|
1488
|
-
mentions: isFirst ? mentionTargets : void 0,
|
|
1489
1511
|
accountId,
|
|
1490
1512
|
header: cardHeader,
|
|
1491
1513
|
note: cardNote
|
|
@@ -1496,14 +1518,13 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1496
1518
|
text,
|
|
1497
1519
|
useCard: false,
|
|
1498
1520
|
infoKind: info?.kind,
|
|
1499
|
-
sendChunk: async ({ chunk
|
|
1521
|
+
sendChunk: async ({ chunk }) => {
|
|
1500
1522
|
await sendMessageFeishu({
|
|
1501
1523
|
cfg,
|
|
1502
1524
|
to: chatId,
|
|
1503
1525
|
text: chunk,
|
|
1504
1526
|
replyToMessageId: sendReplyToMessageId,
|
|
1505
1527
|
replyInThread: effectiveReplyInThread,
|
|
1506
|
-
mentions: isFirst ? mentionTargets : void 0,
|
|
1507
1528
|
accountId
|
|
1508
1529
|
});
|
|
1509
1530
|
}
|
|
@@ -1547,7 +1568,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1547
1568
|
onReasoningStream: reasoningPreviewEnabled ? (payload) => {
|
|
1548
1569
|
if (!payload.text) return;
|
|
1549
1570
|
startStreaming();
|
|
1550
|
-
queueReasoningUpdate(payload.text);
|
|
1571
|
+
queueReasoningUpdate(formatReasoningMessage(payload.text));
|
|
1551
1572
|
} : void 0,
|
|
1552
1573
|
onReasoningEnd: reasoningPreviewEnabled ? () => {} : void 0,
|
|
1553
1574
|
onToolStart: streamingEnabled ? (payload) => {
|
|
@@ -1696,6 +1717,14 @@ function parseFeishuMessageEvent(event, botOpenId, _botName) {
|
|
|
1696
1717
|
}
|
|
1697
1718
|
return ctx;
|
|
1698
1719
|
}
|
|
1720
|
+
const MAX_MENTION_CONTEXT_NAME_LENGTH = 80;
|
|
1721
|
+
function formatMentionNameForAgentContext(name) {
|
|
1722
|
+
const normalized = Array.from(name, (char) => {
|
|
1723
|
+
return char.charCodeAt(0) < 32 || char === "[" || char === "]" ? " " : char;
|
|
1724
|
+
}).join("").replace(/\s+/g, " ").trim();
|
|
1725
|
+
const bounded = normalized.length > MAX_MENTION_CONTEXT_NAME_LENGTH ? `${normalized.slice(0, MAX_MENTION_CONTEXT_NAME_LENGTH - 3)}...` : normalized;
|
|
1726
|
+
return JSON.stringify(bounded || "unknown");
|
|
1727
|
+
}
|
|
1699
1728
|
function buildFeishuAgentBody(params) {
|
|
1700
1729
|
const { ctx, quotedContent, permissionErrorForAgent, botOpenId } = params;
|
|
1701
1730
|
let messageBody = ctx.content;
|
|
@@ -1707,8 +1736,8 @@ function buildFeishuAgentBody(params) {
|
|
|
1707
1736
|
if (botIdHint) messageBody += `\n[System: If user_id is "${botIdHint}", that mention refers to you.]`;
|
|
1708
1737
|
}
|
|
1709
1738
|
if (ctx.mentionTargets && ctx.mentionTargets.length > 0) {
|
|
1710
|
-
const targetNames = ctx.mentionTargets.map((t) => t.name).join(", ");
|
|
1711
|
-
messageBody += `\n\n[System:
|
|
1739
|
+
const targetNames = ctx.mentionTargets.map((t) => formatMentionNameForAgentContext(t.name)).join(", ");
|
|
1740
|
+
messageBody += `\n\n[System: Feishu users mentioned in the incoming message, for context only: ${targetNames}. Do not notify or mention these users solely because they are listed here.]`;
|
|
1712
1741
|
}
|
|
1713
1742
|
messageBody = `[message_id: ${ctx.messageId}]\n${messageBody}`;
|
|
1714
1743
|
if (permissionErrorForAgent) {
|
|
@@ -1717,42 +1746,37 @@ function buildFeishuAgentBody(params) {
|
|
|
1717
1746
|
}
|
|
1718
1747
|
return messageBody;
|
|
1719
1748
|
}
|
|
1720
|
-
function
|
|
1721
|
-
|
|
1722
|
-
if (params.senderType === "app") return true;
|
|
1749
|
+
async function shouldIncludeFetchedGroupContextMessage(params) {
|
|
1750
|
+
let senderAllowed = !params.isGroup || params.allowFrom.length === 0 || params.senderType === "app";
|
|
1723
1751
|
const senderId = params.senderId?.trim();
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
senderName: void 0
|
|
1729
|
-
});
|
|
1730
|
-
}
|
|
1731
|
-
function shouldIncludeFetchedGroupContextMessage(params) {
|
|
1732
|
-
const senderAllowed = isFetchedGroupContextSenderAllowed({
|
|
1733
|
-
isGroup: params.isGroup,
|
|
1752
|
+
if (!senderAllowed && senderId) senderAllowed = (await resolveFeishuGroupSenderActivationIngressAccess({
|
|
1753
|
+
cfg: params.cfg,
|
|
1754
|
+
accountId: params.accountId,
|
|
1755
|
+
chatId: params.chatId,
|
|
1734
1756
|
allowFrom: params.allowFrom,
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1757
|
+
senderOpenId: senderId,
|
|
1758
|
+
senderUserId: senderId,
|
|
1759
|
+
requireMention: false,
|
|
1760
|
+
mentionedBot: true
|
|
1761
|
+
})).senderAccess.decision === "allow";
|
|
1738
1762
|
return evaluateSupplementalContextVisibility({
|
|
1739
1763
|
mode: params.mode,
|
|
1740
1764
|
kind: params.kind,
|
|
1741
1765
|
senderAllowed
|
|
1742
1766
|
}).include;
|
|
1743
1767
|
}
|
|
1744
|
-
function filterFetchedGroupContextMessages(messages, params) {
|
|
1745
|
-
return
|
|
1746
|
-
|
|
1768
|
+
async function filterFetchedGroupContextMessages(messages, params) {
|
|
1769
|
+
return (await Promise.all(messages.map(async (message) => await shouldIncludeFetchedGroupContextMessage({
|
|
1770
|
+
cfg: params.cfg,
|
|
1771
|
+
accountId: params.accountId,
|
|
1772
|
+
chatId: params.chatId,
|
|
1773
|
+
isGroup: params.isGroup,
|
|
1774
|
+
allowFrom: params.allowFrom,
|
|
1747
1775
|
mode: params.mode,
|
|
1748
1776
|
kind: params.kind,
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
senderId: message.senderId,
|
|
1753
|
-
senderType: message.senderType
|
|
1754
|
-
})
|
|
1755
|
-
}).items;
|
|
1777
|
+
senderId: message.senderId,
|
|
1778
|
+
senderType: message.senderType
|
|
1779
|
+
}) ? message : void 0))).filter((message) => message !== void 0);
|
|
1756
1780
|
}
|
|
1757
1781
|
async function handleFeishuMessage(params) {
|
|
1758
1782
|
const { cfg, event, botOpenId, botName, runtime, chatHistories, accountId, processingClaimHeld = false } = params;
|
|
@@ -1873,9 +1897,8 @@ async function handleFeishuMessage(params) {
|
|
|
1873
1897
|
const groupHistoryKey = isGroup ? groupSession?.peerId ?? ctx.chatId : void 0;
|
|
1874
1898
|
const dmPolicy = feishuCfg?.dmPolicy ?? "pairing";
|
|
1875
1899
|
const configAllowFrom = feishuCfg?.allowFrom ?? [];
|
|
1876
|
-
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
|
|
1877
1900
|
const rawBroadcastAgents = isGroup ? resolveBroadcastAgents(cfg, ctx.chatId) : null;
|
|
1878
|
-
const broadcastAgents = rawBroadcastAgents ? [...new Set(rawBroadcastAgents.map((id) => normalizeAgentId(id)))] : null;
|
|
1901
|
+
const broadcastAgents = rawBroadcastAgents ? [...new Set(rawBroadcastAgents.map((id) => normalizeAgentId$1(id)))] : null;
|
|
1879
1902
|
const messageCreateTimeMs = event.message.create_time ? Number.parseInt(event.message.create_time, 10) : Date.now();
|
|
1880
1903
|
let requireMention = false;
|
|
1881
1904
|
if (isGroup) {
|
|
@@ -1900,27 +1923,17 @@ async function handleFeishuMessage(params) {
|
|
|
1900
1923
|
cfg: feishuCfg,
|
|
1901
1924
|
groupId: ctx.chatId
|
|
1902
1925
|
});
|
|
1903
|
-
if (
|
|
1926
|
+
if ((await resolveFeishuGroupConversationIngressAccess({
|
|
1927
|
+
cfg,
|
|
1928
|
+
accountId: account.accountId,
|
|
1929
|
+
chatId: ctx.chatId,
|
|
1904
1930
|
groupPolicy,
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
})))) {
|
|
1931
|
+
groupAllowFrom,
|
|
1932
|
+
groupExplicitlyConfigured
|
|
1933
|
+
})).ingress.admission !== "dispatch") {
|
|
1909
1934
|
log(`feishu[${account.accountId}]: group ${ctx.chatId} not in groupAllowFrom (groupPolicy=${groupPolicy})`);
|
|
1910
1935
|
return;
|
|
1911
1936
|
}
|
|
1912
|
-
if (effectiveGroupSenderAllowFrom.length > 0) {
|
|
1913
|
-
if (!isFeishuGroupAllowed({
|
|
1914
|
-
groupPolicy: "allowlist",
|
|
1915
|
-
allowFrom: effectiveGroupSenderAllowFrom,
|
|
1916
|
-
senderId: ctx.senderOpenId,
|
|
1917
|
-
senderIds: [senderUserId],
|
|
1918
|
-
senderName: ctx.senderName
|
|
1919
|
-
})) {
|
|
1920
|
-
log(`feishu: sender ${ctx.senderOpenId} not in group ${ctx.chatId} sender allowlist`);
|
|
1921
|
-
return;
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
1937
|
({requireMention} = resolveFeishuReplyPolicy({
|
|
1925
1938
|
isDirectMessage: false,
|
|
1926
1939
|
cfg,
|
|
@@ -1928,7 +1941,21 @@ async function handleFeishuMessage(params) {
|
|
|
1928
1941
|
groupId: ctx.chatId,
|
|
1929
1942
|
groupPolicy
|
|
1930
1943
|
}));
|
|
1931
|
-
|
|
1944
|
+
const groupSenderActivationIngress = await resolveFeishuGroupSenderActivationIngressAccess({
|
|
1945
|
+
cfg,
|
|
1946
|
+
accountId: account.accountId,
|
|
1947
|
+
chatId: ctx.chatId,
|
|
1948
|
+
allowFrom: effectiveGroupSenderAllowFrom,
|
|
1949
|
+
senderOpenId: ctx.senderOpenId,
|
|
1950
|
+
senderUserId,
|
|
1951
|
+
requireMention,
|
|
1952
|
+
mentionedBot: ctx.mentionedBot
|
|
1953
|
+
});
|
|
1954
|
+
if (groupSenderActivationIngress.senderAccess.decision !== "allow") {
|
|
1955
|
+
log(`feishu: sender ${ctx.senderOpenId} not in group ${ctx.chatId} sender allowlist`);
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
if (groupSenderActivationIngress.ingress.admission !== "dispatch") {
|
|
1932
1959
|
log(`feishu[${account.accountId}]: message in group ${ctx.chatId} did not mention bot`);
|
|
1933
1960
|
if (!broadcastAgents && chatHistories && groupHistoryKey) recordPendingHistoryEntryIfEnabled({
|
|
1934
1961
|
historyMap: chatHistories,
|
|
@@ -1953,25 +1980,20 @@ async function handleFeishuMessage(params) {
|
|
|
1953
1980
|
});
|
|
1954
1981
|
const commandProbeBody = isGroup ? normalizeFeishuCommandProbeBody(ctx.content) : ctx.content;
|
|
1955
1982
|
const shouldComputeCommandAuthorized = core.channel.commands.shouldComputeCommandAuthorized(commandProbeBody, cfg);
|
|
1956
|
-
const
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
senderName: ctx.senderName
|
|
1971
|
-
}).allowed
|
|
1972
|
-
}).decision === "allow" : dmAllowed;
|
|
1973
|
-
if (isDirect && !dmAccessAllowed) {
|
|
1974
|
-
if (dmPolicy === "pairing") await pairing.issueChallenge({
|
|
1983
|
+
const dmIngress = isDirect ? await resolveFeishuDmIngressAccess({
|
|
1984
|
+
cfg,
|
|
1985
|
+
accountId: account.accountId,
|
|
1986
|
+
dmPolicy,
|
|
1987
|
+
allowFrom: configAllowFrom,
|
|
1988
|
+
readAllowFromStore: pairing.readAllowFromStore,
|
|
1989
|
+
senderOpenId: ctx.senderOpenId,
|
|
1990
|
+
senderUserId,
|
|
1991
|
+
conversationId: ctx.senderOpenId,
|
|
1992
|
+
mayPair: true,
|
|
1993
|
+
...shouldComputeCommandAuthorized ? { command: { hasControlCommand: true } } : {}
|
|
1994
|
+
}) : null;
|
|
1995
|
+
if (isDirect && dmIngress?.ingress.admission !== "dispatch") {
|
|
1996
|
+
if (dmIngress?.ingress.admission === "pairing-required") await pairing.issueChallenge({
|
|
1975
1997
|
senderId: ctx.senderOpenId,
|
|
1976
1998
|
senderIdLine: `Your Feishu user id: ${ctx.senderOpenId}`,
|
|
1977
1999
|
meta: { name: ctx.senderName },
|
|
@@ -1993,13 +2015,7 @@ async function handleFeishuMessage(params) {
|
|
|
1993
2015
|
else log(`feishu[${account.accountId}]: blocked unauthorized sender ${ctx.senderOpenId} (dmPolicy=${dmPolicy})`);
|
|
1994
2016
|
return;
|
|
1995
2017
|
}
|
|
1996
|
-
const commandAllowFrom = isGroup ? groupConfig?.allowFrom ?? configAllowFrom :
|
|
1997
|
-
const senderAllowedForCommands = resolveFeishuAllowlistMatch({
|
|
1998
|
-
allowFrom: commandAllowFrom,
|
|
1999
|
-
senderId: ctx.senderOpenId,
|
|
2000
|
-
senderIds: [senderUserId],
|
|
2001
|
-
senderName: ctx.senderName
|
|
2002
|
-
}).allowed;
|
|
2018
|
+
const commandAllowFrom = isGroup ? groupConfig?.allowFrom ?? configAllowFrom : dmIngress?.senderAccess.effectiveAllowFrom ?? configAllowFrom;
|
|
2003
2019
|
const feishuFrom = `feishu:${ctx.senderOpenId}`;
|
|
2004
2020
|
const feishuTo = isGroup ? `chat:${ctx.chatId}` : `user:${ctx.senderOpenId}`;
|
|
2005
2021
|
const peerId = isGroup ? groupSession?.peerId ?? ctx.chatId : ctx.senderOpenId;
|
|
@@ -2026,6 +2042,11 @@ async function handleFeishuMessage(params) {
|
|
|
2026
2042
|
runtime: getFeishuRuntime(),
|
|
2027
2043
|
senderOpenId: ctx.senderOpenId,
|
|
2028
2044
|
dynamicCfg,
|
|
2045
|
+
configWritesAllowed: resolveChannelConfigWrites({
|
|
2046
|
+
cfg,
|
|
2047
|
+
channelId: "feishu",
|
|
2048
|
+
accountId: account.accountId
|
|
2049
|
+
}),
|
|
2029
2050
|
log: (msg) => log(msg)
|
|
2030
2051
|
});
|
|
2031
2052
|
if (result.created) {
|
|
@@ -2131,13 +2152,28 @@ async function handleFeishuMessage(params) {
|
|
|
2131
2152
|
content: audioTranscript
|
|
2132
2153
|
};
|
|
2133
2154
|
const effectiveCommandProbeBody = audioTranscript === void 0 ? commandProbeBody : isGroup ? normalizeFeishuCommandProbeBody(audioTranscript) : audioTranscript;
|
|
2134
|
-
const commandAuthorized = (audioTranscript === void 0 ? shouldComputeCommandAuthorized : core.channel.commands.shouldComputeCommandAuthorized(effectiveCommandProbeBody, cfg)) ?
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2155
|
+
const commandAuthorized = (audioTranscript === void 0 ? shouldComputeCommandAuthorized : core.channel.commands.shouldComputeCommandAuthorized(effectiveCommandProbeBody, cfg)) ? isDirect && audioTranscript === void 0 && dmIngress ? dmIngress.commandAccess.authorized : isGroup ? (await resolveFeishuGroupSenderActivationIngressAccess({
|
|
2156
|
+
cfg,
|
|
2157
|
+
accountId: account.accountId,
|
|
2158
|
+
chatId: ctx.chatId,
|
|
2159
|
+
allowFrom: commandAllowFrom,
|
|
2160
|
+
senderOpenId: ctx.senderOpenId,
|
|
2161
|
+
senderUserId,
|
|
2162
|
+
requireMention: false,
|
|
2163
|
+
mentionedBot: true,
|
|
2164
|
+
command: { hasControlCommand: true }
|
|
2165
|
+
})).commandAccess.authorized : (await resolveFeishuDmIngressAccess({
|
|
2166
|
+
cfg,
|
|
2167
|
+
accountId: account.accountId,
|
|
2168
|
+
dmPolicy,
|
|
2169
|
+
allowFrom: configAllowFrom,
|
|
2170
|
+
readAllowFromStore: pairing.readAllowFromStore,
|
|
2171
|
+
senderOpenId: ctx.senderOpenId,
|
|
2172
|
+
senderUserId,
|
|
2173
|
+
conversationId: ctx.senderOpenId,
|
|
2174
|
+
mayPair: false,
|
|
2175
|
+
command: { hasControlCommand: true }
|
|
2176
|
+
})).commandAccess.authorized : void 0;
|
|
2141
2177
|
let quotedMessageInfo = null;
|
|
2142
2178
|
let quotedContent;
|
|
2143
2179
|
if (ctx.parentId) try {
|
|
@@ -2146,7 +2182,10 @@ async function handleFeishuMessage(params) {
|
|
|
2146
2182
|
messageId: ctx.parentId,
|
|
2147
2183
|
accountId: account.accountId
|
|
2148
2184
|
});
|
|
2149
|
-
if (quotedMessageInfo && shouldIncludeFetchedGroupContextMessage({
|
|
2185
|
+
if (quotedMessageInfo && await shouldIncludeFetchedGroupContextMessage({
|
|
2186
|
+
cfg,
|
|
2187
|
+
accountId: account.accountId,
|
|
2188
|
+
chatId: ctx.chatId,
|
|
2150
2189
|
isGroup,
|
|
2151
2190
|
allowFrom: effectiveGroupSenderAllowFrom,
|
|
2152
2191
|
mode: contextVisibilityMode,
|
|
@@ -2216,7 +2255,10 @@ async function handleFeishuMessage(params) {
|
|
|
2216
2255
|
rootMessageInfo = null;
|
|
2217
2256
|
}
|
|
2218
2257
|
rootMessageThreadId = rootMessageInfo?.threadId;
|
|
2219
|
-
if (rootMessageInfo && !shouldIncludeFetchedGroupContextMessage({
|
|
2258
|
+
if (rootMessageInfo && !await shouldIncludeFetchedGroupContextMessage({
|
|
2259
|
+
cfg,
|
|
2260
|
+
accountId: account.accountId,
|
|
2261
|
+
chatId: ctx.chatId,
|
|
2220
2262
|
isGroup,
|
|
2221
2263
|
allowFrom: effectiveGroupSenderAllowFrom,
|
|
2222
2264
|
mode: contextVisibilityMode,
|
|
@@ -2276,7 +2318,10 @@ async function handleFeishuMessage(params) {
|
|
|
2276
2318
|
});
|
|
2277
2319
|
const senderScoped = groupSession?.groupSessionScope === "group_topic_sender";
|
|
2278
2320
|
const senderIds = new Set([ctx.senderOpenId, senderUserId].map((id) => id?.trim()).filter((id) => id !== void 0 && id.length > 0));
|
|
2279
|
-
const allowlistedMessages = filterFetchedGroupContextMessages(threadMessages, {
|
|
2321
|
+
const allowlistedMessages = await filterFetchedGroupContextMessages(threadMessages, {
|
|
2322
|
+
cfg,
|
|
2323
|
+
accountId: account.accountId,
|
|
2324
|
+
chatId: ctx.chatId,
|
|
2280
2325
|
isGroup,
|
|
2281
2326
|
allowFrom: effectiveGroupSenderAllowFrom,
|
|
2282
2327
|
mode: contextVisibilityMode,
|
|
@@ -2353,12 +2398,12 @@ async function handleFeishuMessage(params) {
|
|
|
2353
2398
|
return;
|
|
2354
2399
|
}
|
|
2355
2400
|
const strategy = cfg.broadcast?.strategy === "sequential" ? "sequential" : "parallel";
|
|
2356
|
-
const activeAgentId = ctx.mentionedBot || !requireMention ? normalizeAgentId(route.agentId) : null;
|
|
2357
|
-
const agentIds = (cfg.agents?.list ?? []).map((a) => normalizeAgentId(a.id));
|
|
2401
|
+
const activeAgentId = ctx.mentionedBot || !requireMention ? normalizeAgentId$1(route.agentId) : null;
|
|
2402
|
+
const agentIds = (cfg.agents?.list ?? []).map((a) => normalizeAgentId$1(a.id));
|
|
2358
2403
|
const hasKnownAgents = agentIds.length > 0;
|
|
2359
2404
|
log(`feishu[${account.accountId}]: broadcasting to ${broadcastAgents.length} agents (strategy=${strategy}, active=${activeAgentId ?? "none"})`);
|
|
2360
2405
|
const dispatchForAgent = async (agentId) => {
|
|
2361
|
-
if (hasKnownAgents && !agentIds.includes(normalizeAgentId(agentId))) {
|
|
2406
|
+
if (hasKnownAgents && !agentIds.includes(normalizeAgentId$1(agentId))) {
|
|
2362
2407
|
log(`feishu[${account.accountId}]: broadcast agent ${agentId} not found in agents.list; skipping`);
|
|
2363
2408
|
return;
|
|
2364
2409
|
}
|
|
@@ -2368,6 +2413,8 @@ async function handleFeishuMessage(params) {
|
|
|
2368
2413
|
log(`feishu[${account.accountId}]: failed to record broadcast inbound session ${agentSessionKey}: ${String(err)}`);
|
|
2369
2414
|
} };
|
|
2370
2415
|
const allowReasoningPreview = resolveFeishuReasoningPreviewEnabled({
|
|
2416
|
+
cfg,
|
|
2417
|
+
agentId,
|
|
2371
2418
|
storePath: agentStorePath,
|
|
2372
2419
|
sessionKey: agentSessionKey
|
|
2373
2420
|
});
|
|
@@ -2385,7 +2432,6 @@ async function handleFeishuMessage(params) {
|
|
|
2385
2432
|
replyInThread,
|
|
2386
2433
|
rootId: ctx.rootId,
|
|
2387
2434
|
threadReply,
|
|
2388
|
-
mentionTargets: ctx.mentionTargets,
|
|
2389
2435
|
accountId: account.accountId,
|
|
2390
2436
|
identity,
|
|
2391
2437
|
messageCreateTimeMs
|
|
@@ -2503,6 +2549,8 @@ async function handleFeishuMessage(params) {
|
|
|
2503
2549
|
const identity = resolveAgentOutboundIdentity(cfg, route.agentId);
|
|
2504
2550
|
const storePath = core.channel.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
|
|
2505
2551
|
const allowReasoningPreview = resolveFeishuReasoningPreviewEnabled({
|
|
2552
|
+
cfg,
|
|
2553
|
+
agentId: route.agentId,
|
|
2506
2554
|
storePath,
|
|
2507
2555
|
sessionKey: route.sessionKey
|
|
2508
2556
|
});
|
|
@@ -2517,7 +2565,6 @@ async function handleFeishuMessage(params) {
|
|
|
2517
2565
|
replyInThread,
|
|
2518
2566
|
rootId: ctx.rootId,
|
|
2519
2567
|
threadReply,
|
|
2520
|
-
mentionTargets: ctx.mentionTargets,
|
|
2521
2568
|
accountId: account.accountId,
|
|
2522
2569
|
identity,
|
|
2523
2570
|
messageCreateTimeMs
|
|
@@ -3941,22 +3988,19 @@ async function handleFeishuCommentEvent(params) {
|
|
|
3941
3988
|
channel: "feishu",
|
|
3942
3989
|
accountId: account.accountId
|
|
3943
3990
|
});
|
|
3944
|
-
const
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
}).allowed
|
|
3958
|
-
}).decision === "allow" : senderAllowed)) {
|
|
3959
|
-
if (dmPolicy === "pairing") {
|
|
3991
|
+
const dmIngress = await resolveFeishuDmIngressAccess({
|
|
3992
|
+
cfg: params.cfg,
|
|
3993
|
+
accountId: account.accountId,
|
|
3994
|
+
dmPolicy,
|
|
3995
|
+
allowFrom: configAllowFrom,
|
|
3996
|
+
readAllowFromStore: pairing.readAllowFromStore,
|
|
3997
|
+
senderOpenId: turn.senderId,
|
|
3998
|
+
senderUserId: turn.senderUserId,
|
|
3999
|
+
conversationId: turn.senderId,
|
|
4000
|
+
mayPair: true
|
|
4001
|
+
});
|
|
4002
|
+
if (dmIngress.ingress.admission !== "dispatch") {
|
|
4003
|
+
if (dmIngress.ingress.admission === "pairing-required") {
|
|
3960
4004
|
const client = createFeishuClient(account);
|
|
3961
4005
|
await pairing.issueChallenge({
|
|
3962
4006
|
senderId: turn.senderId,
|
|
@@ -3999,6 +4043,11 @@ async function handleFeishuCommentEvent(params) {
|
|
|
3999
4043
|
runtime: core,
|
|
4000
4044
|
senderOpenId: turn.senderId,
|
|
4001
4045
|
dynamicCfg,
|
|
4046
|
+
configWritesAllowed: resolveChannelConfigWrites({
|
|
4047
|
+
cfg: params.cfg,
|
|
4048
|
+
channelId: "feishu",
|
|
4049
|
+
accountId: account.accountId
|
|
4050
|
+
}),
|
|
4002
4051
|
log: (message) => log(message)
|
|
4003
4052
|
});
|
|
4004
4053
|
if (dynamicResult.created) {
|