@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 CHANGED
@@ -2,7 +2,7 @@ import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as bu
2
2
  import { n as createFeishuThreadBindingManager, r as getFeishuThreadBindingManager, t as __testing } from "./thread-bindings-BmS6TLes.js";
3
3
  import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-C3UhPVLV.js";
4
4
  import { r as listEnabledFeishuAccounts } from "./accounts-Ba3-WP1z.js";
5
- import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-BegH3cJm.js";
5
+ import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-DCSECj4a.js";
6
6
  import { t as getFeishuRuntime } from "./runtime-CG0DuRCy.js";
7
7
  import { a as jsonToolResult, d as registerFeishuChatTools, f as createFeishuToolClient, m as resolveFeishuToolAccount, n as registerFeishuDriveTools, o as toolExecutionErrorResult, p as resolveAnyEnabledFeishuToolsConfig, s as unknownToolActionResult } from "./drive-C5eJLJr7.js";
8
8
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime";
@@ -10,6 +10,7 @@ import { existsSync } from "node:fs";
10
10
  import { homedir } from "node:os";
11
11
  import { basename, isAbsolute, resolve } from "node:path";
12
12
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
13
+ import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
13
14
  import { Type } from "typebox";
14
15
  import { createClackPrompter } from "openclaw/plugin-sdk/setup-runtime";
15
16
  //#region extensions/feishu/src/doc-schema.ts
@@ -879,7 +880,7 @@ async function resolveUploadInput(url, filePath, maxBytes, localRoots, explicitF
879
880
  if (!header.includes(";base64")) throw new Error("Invalid data URI: missing ';base64' marker. Expected format: data:image/png;base64,<base64data>");
880
881
  const trimmedData = data.trim();
881
882
  if (trimmedData.length === 0 || !/^[A-Za-z0-9+/]+=*$/.test(trimmedData)) throw new Error(`Invalid data URI: base64 payload contains characters outside the standard alphabet.`);
882
- const ext = header.match(/data:([^;]+)/)?.[1]?.split("/")[1] ?? "png";
883
+ const ext = extensionForMime(header.match(/data:([^;]+)/)?.[1])?.slice(1) ?? "png";
883
884
  const estimatedBytes = Math.ceil(trimmedData.length * 3 / 4);
884
885
  if (estimatedBytes > maxBytes) throw new Error(`Image data URI exceeds limit: estimated ${estimatedBytes} bytes > ${maxBytes} bytes`);
885
886
  return {
@@ -1,10 +1,10 @@
1
1
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-DWS3Ep2A.js";
2
2
  import { n as looksLikeFeishuId, r as normalizeFeishuTarget } from "./targets-JMFJRKSe.js";
3
3
  import { a as resolveDefaultFeishuAccountId, f as isRecord$1, i as listFeishuAccountIds, n as inspectFeishuCredentials, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-Ba3-WP1z.js";
4
- import "./card-interaction-BfRLgvw_.js";
4
+ import { n as createFeishuSendReceipt } from "./send-result-BVFTskB_.js";
5
5
  import { n as listFeishuDirectoryPeers, t as listFeishuDirectoryGroups } from "./directory.static-f3EeoRJd.js";
6
6
  import { t as messageActionTargetAliases } from "./security-audit-DqJdocrN.js";
7
- import { a as resolveFeishuGroupToolPolicy } from "./policy-D6c-wMPl.js";
7
+ import { o as resolveFeishuGroupToolPolicy } from "./policy-DrLgxWF_.js";
8
8
  import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Dm4Z_zQN.js";
9
9
  import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-ByuMx9cJ.js";
10
10
  import { t as resolveFeishuSessionConversation } from "./session-conversation-B4nrW-vo.js";
@@ -14,6 +14,7 @@ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
14
14
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
15
15
  import { adaptScopedAccountAccessor, createHybridChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
16
16
  import { buildChannelOutboundSessionRoute, createChatChannelPlugin, stripChannelTargetPrefix } from "openclaw/plugin-sdk/channel-core";
17
+ import { defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-message";
17
18
  import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
18
19
  import { createAllowlistProviderGroupPolicyWarningCollector, projectConfigAccountIdWarningCollector } from "openclaw/plugin-sdk/channel-policy";
19
20
  import { createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter } from "openclaw/plugin-sdk/directory-runtime";
@@ -810,7 +811,37 @@ const meta = {
810
811
  aliases: ["lark"],
811
812
  order: 70
812
813
  };
813
- const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-DYsXcD36.js"), "feishuChannelRuntime");
814
+ const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-BlDkd6xR.js"), "feishuChannelRuntime");
815
+ function toFeishuMessageSendResult(result, kind) {
816
+ const receipt = result.receipt ?? createFeishuSendReceipt({
817
+ messageId: result.messageId,
818
+ chatId: result.chatId ?? "",
819
+ kind
820
+ });
821
+ return {
822
+ messageId: result.messageId || receipt.primaryPlatformMessageId,
823
+ receipt
824
+ };
825
+ }
826
+ const feishuMessageAdapter = defineChannelMessageAdapter({
827
+ id: "feishu",
828
+ durableFinal: { capabilities: {
829
+ text: true,
830
+ media: true
831
+ } },
832
+ send: {
833
+ text: async (ctx) => {
834
+ const sendText = (await loadFeishuChannelRuntime()).feishuOutbound.sendText;
835
+ if (!sendText) throw new Error("Feishu text sending is not available.");
836
+ return toFeishuMessageSendResult(await sendText(ctx), "text");
837
+ },
838
+ media: async (ctx) => {
839
+ const sendMedia = (await loadFeishuChannelRuntime()).feishuOutbound.sendMedia;
840
+ if (!sendMedia) throw new Error("Feishu media sending is not available.");
841
+ return toFeishuMessageSendResult(await sendMedia(ctx), "media");
842
+ }
843
+ }
844
+ });
814
845
  function buildFeishuPresentationCard(params) {
815
846
  const fallbackPresentation = {
816
847
  ...params.presentation.tone ? { tone: params.presentation.tone } : {},
@@ -926,6 +957,28 @@ function areAnyFeishuReactionActionsEnabled(cfg) {
926
957
  })) return true;
927
958
  return false;
928
959
  }
960
+ function isFeishuGroupTopicSessionKey(sessionKey) {
961
+ if (typeof sessionKey !== "string" || !sessionKey) return false;
962
+ const parsed = parseFeishuConversationId({ conversationId: sessionKey });
963
+ return parsed?.scope === "group_topic" || parsed?.scope === "group_topic_sender";
964
+ }
965
+ function resolveFeishuTopicAutoThreadAnchor(ctx) {
966
+ if (ctx.action !== "send") return;
967
+ if (!isFeishuGroupTopicSessionKey(ctx.sessionKey)) return;
968
+ const inbound = ctx.toolContext?.currentMessageId;
969
+ return typeof inbound === "string" && inbound.length > 0 ? inbound : void 0;
970
+ }
971
+ function buildFeishuSendReplyAnchor(ctx) {
972
+ if (ctx.action === "thread-reply") return {
973
+ replyToMessageId: resolveFeishuMessageId(ctx.params),
974
+ replyInThread: true
975
+ };
976
+ const autoThreadId = resolveFeishuTopicAutoThreadAnchor(ctx);
977
+ return {
978
+ replyToMessageId: autoThreadId,
979
+ replyInThread: autoThreadId !== void 0
980
+ };
981
+ }
929
982
  function isSupportedFeishuDirectConversationId(conversationId) {
930
983
  const trimmed = conversationId.trim();
931
984
  if (!trimmed || trimmed.includes(":")) return false;
@@ -1182,7 +1235,7 @@ const feishuPlugin = createChatChannelPlugin({
1182
1235
  if (ctx.action === "send" || ctx.action === "thread-reply") {
1183
1236
  const to = resolveFeishuActionTarget(ctx);
1184
1237
  if (!to) throw new Error(`Feishu ${ctx.action} requires a target (to).`);
1185
- const replyToMessageId = ctx.action === "thread-reply" ? resolveFeishuMessageId(ctx.params) : void 0;
1238
+ const { replyToMessageId, replyInThread } = buildFeishuSendReplyAnchor(ctx);
1186
1239
  if (ctx.action === "thread-reply" && !replyToMessageId) throw new Error("Feishu thread-reply requires messageId.");
1187
1240
  const presentation = normalizeMessagePresentation(ctx.params.presentation);
1188
1241
  const text = readFirstString(ctx.params, ["text", "message"]);
@@ -1207,7 +1260,7 @@ const feishuPlugin = createChatChannelPlugin({
1207
1260
  card,
1208
1261
  accountId: ctx.accountId ?? void 0,
1209
1262
  replyToMessageId,
1210
- replyInThread: ctx.action === "thread-reply"
1263
+ replyInThread
1211
1264
  });
1212
1265
  } else if (mediaUrl) result = await sendMedia({
1213
1266
  cfg: ctx.cfg,
@@ -1216,7 +1269,7 @@ const feishuPlugin = createChatChannelPlugin({
1216
1269
  mediaUrl,
1217
1270
  accountId: ctx.accountId ?? void 0,
1218
1271
  mediaLocalRoots: ctx.mediaLocalRoots,
1219
- replyToId: replyToMessageId,
1272
+ ...replyInThread ? { threadId: replyToMessageId } : { replyToId: replyToMessageId },
1220
1273
  ...audioAsVoice === true ? { audioAsVoice: true } : {}
1221
1274
  });
1222
1275
  else result = await runtime.sendMessageFeishu({
@@ -1225,7 +1278,7 @@ const feishuPlugin = createChatChannelPlugin({
1225
1278
  text,
1226
1279
  accountId: ctx.accountId ?? void 0,
1227
1280
  replyToMessageId,
1228
- replyInThread: ctx.action === "thread-reply"
1281
+ replyInThread
1229
1282
  });
1230
1283
  return jsonActionResult({
1231
1284
  ok: true,
@@ -1601,7 +1654,7 @@ const feishuPlugin = createChatChannelPlugin({
1601
1654
  })
1602
1655
  }),
1603
1656
  gateway: { startAccount: async (ctx) => {
1604
- const { monitorFeishuProvider } = await import("./monitor-BVR-x39Q.js");
1657
+ const { monitorFeishuProvider } = await import("./monitor-BnbCJWIU.js");
1605
1658
  const account = resolveFeishuRuntimeAccount({
1606
1659
  cfg: ctx.cfg,
1607
1660
  accountId: ctx.accountId
@@ -1618,7 +1671,8 @@ const feishuPlugin = createChatChannelPlugin({
1618
1671
  abortSignal: ctx.abortSignal,
1619
1672
  accountId: ctx.accountId
1620
1673
  });
1621
- } }
1674
+ } },
1675
+ message: feishuMessageAdapter
1622
1676
  },
1623
1677
  security: {
1624
1678
  collectWarnings: projectConfigAccountIdWarningCollector(collectFeishuSecurityWarnings),
@@ -1,2 +1,2 @@
1
- import { t as feishuPlugin } from "./channel-BegH3cJm.js";
1
+ import { t as feishuPlugin } from "./channel-DCSECj4a.js";
2
2
  export { feishuPlugin };
@@ -1,17 +1,17 @@
1
1
  import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, y as parseFeishuCommentTarget } from "./accounts-Ba3-WP1z.js";
2
- import { r as createFeishuCardInteractionEnvelope } from "./card-interaction-BfRLgvw_.js";
2
+ import { s as createFeishuCardInteractionEnvelope } from "./send-result-BVFTskB_.js";
3
3
  import { n as listFeishuDirectoryPeers, t as listFeishuDirectoryGroups } from "./directory.static-f3EeoRJd.js";
4
4
  import { r as createFeishuClient } from "./client-DBVoQL5w.js";
5
5
  import { c as getChatInfo, l as getChatMembers, r as cleanupAmbientCommentTypingReaction, t as deliverCommentThreadText, u as getFeishuMemberInfo } from "./drive-C5eJLJr7.js";
6
6
  import { chunkTextForOutbound } from "./runtime-api.js";
7
- import { _ as shouldSuppressFeishuTextForVoiceMedia, a as sendCardFeishu, c as sendStructuredCardFeishu, g as sendMediaFeishu, i as resolveFeishuCardTemplate, n as getMessageFeishu, o as sendMarkdownCardFeishu, s as sendMessageFeishu, t as editMessageFeishu } from "./send-DowxxbpH.js";
7
+ import { a as sendCardFeishu, c as sendStructuredCardFeishu, g as shouldSuppressFeishuTextForVoiceMedia, h as sendMediaFeishu, i as resolveFeishuCardTemplate, n as getMessageFeishu, o as sendMarkdownCardFeishu, s as sendMessageFeishu, t as editMessageFeishu } from "./send-DKHEQrzH.js";
8
8
  import { t as probeFeishu } from "./probe-BNzzU_uR.js";
9
9
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
10
10
  import { interactiveReplyToPresentation, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
11
- import fs from "node:fs";
12
11
  import path from "node:path";
13
12
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
14
13
  import { resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
14
+ import { statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
15
15
  //#region extensions/feishu/src/directory.ts
16
16
  async function listFeishuDirectoryPeersLive(params) {
17
17
  const account = resolveFeishuAccount({
@@ -93,9 +93,8 @@ function normalizePossibleLocalImagePath(text) {
93
93
  ".tiff"
94
94
  ].includes(ext)) return null;
95
95
  if (!path.isAbsolute(raw)) return null;
96
- if (!fs.existsSync(raw)) return null;
97
96
  try {
98
- if (!fs.statSync(raw).isFile()) return null;
97
+ if (statRegularFileSync(raw).missing) return null;
99
98
  } catch {
100
99
  return null;
101
100
  }
@@ -314,6 +313,13 @@ function resolveReplyToMessageId(params) {
314
313
  if (params.threadId == null) return;
315
314
  return String(params.threadId).trim() || void 0;
316
315
  }
316
+ function resolveFeishuMediaReplyMode(params) {
317
+ const trimmedReplyToId = params.replyToId?.trim() || void 0;
318
+ return {
319
+ replyToMessageId: resolveReplyToMessageId(params),
320
+ replyInThread: params.threadId != null && !trimmedReplyToId
321
+ };
322
+ }
317
323
  async function sendCommentThreadReply(params) {
318
324
  const target = parseFeishuCommentTarget(params.to);
319
325
  if (!target) return null;
@@ -346,7 +352,7 @@ async function sendCommentThreadReply(params) {
346
352
  }
347
353
  }
348
354
  async function sendOutboundText(params) {
349
- const { cfg, to, text, accountId, replyToMessageId } = params;
355
+ const { cfg, to, text, accountId, replyToMessageId, replyInThread } = params;
350
356
  const commentResult = await sendCommentThreadReply({
351
357
  cfg,
352
358
  to,
@@ -364,14 +370,16 @@ async function sendOutboundText(params) {
364
370
  to,
365
371
  text,
366
372
  accountId,
367
- replyToMessageId
373
+ replyToMessageId,
374
+ replyInThread
368
375
  });
369
376
  return sendMessageFeishu({
370
377
  cfg,
371
378
  to,
372
379
  text,
373
380
  accountId,
374
- replyToMessageId
381
+ replyToMessageId,
382
+ replyInThread
375
383
  });
376
384
  }
377
385
  const feishuOutbound = {
@@ -448,7 +456,7 @@ const feishuOutbound = {
448
456
  ...createAttachedChannelResultAdapter({
449
457
  channel: "feishu",
450
458
  sendText: async ({ cfg, to, text, accountId, replyToId, threadId, mediaLocalRoots, identity }) => {
451
- const replyToMessageId = resolveReplyToMessageId({
459
+ const { replyToMessageId, replyInThread } = resolveFeishuMediaReplyMode({
452
460
  replyToId,
453
461
  threadId
454
462
  });
@@ -460,6 +468,7 @@ const feishuOutbound = {
460
468
  mediaUrl: localImagePath,
461
469
  accountId: accountId ?? void 0,
462
470
  replyToMessageId,
471
+ replyInThread,
463
472
  mediaLocalRoots
464
473
  });
465
474
  } catch (err) {
@@ -470,7 +479,8 @@ const feishuOutbound = {
470
479
  to,
471
480
  text,
472
481
  accountId: accountId ?? void 0,
473
- replyToMessageId
482
+ replyToMessageId,
483
+ replyInThread
474
484
  });
475
485
  const renderMode = resolveFeishuAccount({
476
486
  cfg,
@@ -486,7 +496,7 @@ const feishuOutbound = {
486
496
  to,
487
497
  text,
488
498
  replyToMessageId,
489
- replyInThread: threadId != null && !replyToId,
499
+ replyInThread,
490
500
  accountId: accountId ?? void 0,
491
501
  header: header?.title ? header : void 0
492
502
  });
@@ -496,11 +506,12 @@ const feishuOutbound = {
496
506
  to,
497
507
  text,
498
508
  accountId: accountId ?? void 0,
499
- replyToMessageId
509
+ replyToMessageId,
510
+ replyInThread
500
511
  });
501
512
  },
502
513
  sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaLocalRoots, replyToId, threadId }) => {
503
- const replyToMessageId = resolveReplyToMessageId({
514
+ const { replyToMessageId, replyInThread } = resolveFeishuMediaReplyMode({
504
515
  replyToId,
505
516
  threadId
506
517
  });
@@ -509,7 +520,8 @@ const feishuOutbound = {
509
520
  to,
510
521
  text: [text?.trim(), mediaUrl?.trim()].filter(Boolean).join("\n\n") || mediaUrl || text || "",
511
522
  accountId: accountId ?? void 0,
512
- replyToMessageId
523
+ replyToMessageId,
524
+ replyInThread
513
525
  });
514
526
  const suppressTextForVoiceMedia = mediaUrl !== void 0 && shouldSuppressFeishuTextForVoiceMedia({
515
527
  mediaUrl,
@@ -520,7 +532,8 @@ const feishuOutbound = {
520
532
  to,
521
533
  text,
522
534
  accountId: accountId ?? void 0,
523
- replyToMessageId
535
+ replyToMessageId,
536
+ replyInThread
524
537
  });
525
538
  if (mediaUrl) try {
526
539
  const result = await sendMediaFeishu({
@@ -530,6 +543,7 @@ const feishuOutbound = {
530
543
  accountId: accountId ?? void 0,
531
544
  mediaLocalRoots,
532
545
  replyToMessageId,
546
+ replyInThread,
533
547
  ...audioAsVoice === true ? { audioAsVoice: true } : {}
534
548
  });
535
549
  if (result.voiceIntentDegradedToFile && text?.trim()) await sendOutboundText({
@@ -537,7 +551,8 @@ const feishuOutbound = {
537
551
  to,
538
552
  text,
539
553
  accountId: accountId ?? void 0,
540
- replyToMessageId
554
+ replyToMessageId,
555
+ replyInThread
541
556
  });
542
557
  return result;
543
558
  } catch (err) {
@@ -547,7 +562,8 @@ const feishuOutbound = {
547
562
  to,
548
563
  text: [text?.trim(), `📎 ${mediaUrl}`].filter(Boolean).join("\n\n"),
549
564
  accountId: accountId ?? void 0,
550
- replyToMessageId
565
+ replyToMessageId,
566
+ replyInThread
551
567
  });
552
568
  }
553
569
  return await sendOutboundText({
@@ -555,7 +571,8 @@ const feishuOutbound = {
555
571
  to,
556
572
  text: text ?? "",
557
573
  accountId: accountId ?? void 0,
558
- replyToMessageId
574
+ replyToMessageId,
575
+ replyInThread
559
576
  });
560
577
  }
561
578
  })
@@ -3,7 +3,7 @@ import { l as fetchBotIdentityForMonitor } from "./monitor.state-DYM02ipp.js";
3
3
  //#region extensions/feishu/src/monitor.ts
4
4
  let monitorAccountRuntimePromise;
5
5
  async function loadMonitorAccountRuntime() {
6
- monitorAccountRuntimePromise ??= import("./monitor.account-CUZxYkjE.js");
6
+ monitorAccountRuntimePromise ??= import("./monitor.account-88yMtLAU.js");
7
7
  return await monitorAccountRuntimePromise;
8
8
  }
9
9
  async function monitorFeishuProvider(opts = {}) {