@openclaw/feishu 2026.8.1-beta.2 → 2026.8.1-beta.3

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
@@ -1,12 +1,12 @@
1
1
  import { r as listEnabledFeishuAccounts } from "./accounts-CCCdMen2.js";
2
- import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-Dzb5jv3i.js";
2
+ import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-Ceq80_zP.js";
3
3
  import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-DEAycmOk.js";
4
4
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
5
- import { r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-Hp7uo_cl.js";
5
+ import { s as resolveConfiguredHttpTimeoutMs } from "./client-Hp7uo_cl.js";
6
6
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
7
- import { C as resolveFeishuToolAccount, S as resolveAnyEnabledFeishuToolsConfig, b as unknownToolActionResult, n as registerFeishuDriveTools, u as registerFeishuChatTools, v as feishuExternalToolResult, w as resolveToolsConfig, x as createFeishuToolClient, y as toolExecutionErrorResult } from "./drive-B0JkoiRj.js";
8
- import { n as getFeishuThreadBindingManager, t as createFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
9
- import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-B867acTt.js";
7
+ import { C as resolveFeishuToolAccount, S as resolveAnyEnabledFeishuToolsConfig, b as unknownToolActionResult, n as registerFeishuDriveTools, u as registerFeishuChatTools, v as feishuExternalToolResult, x as createFeishuToolClient, y as toolExecutionErrorResult } from "./drive-BVYM_Y4k.js";
8
+ import { n as getFeishuThreadBindingManager, t as createFeishuThreadBindingManager } from "./thread-bindings-CptM_YU6.js";
9
+ import { n as handleFeishuSubagentEnded, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-KUi-7vUy.js";
10
10
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
11
11
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
12
12
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, readStringValue, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -2440,15 +2440,15 @@ function registerFeishuBitableTools(api) {
2440
2440
  const accounts = listEnabledFeishuAccounts(api.config);
2441
2441
  if (accounts.length === 0) return;
2442
2442
  if (!resolveAnyEnabledFeishuToolsConfig(accounts).bitable) return;
2443
- const getClient = (params, defaultAccountId) => {
2444
- const account = resolveFeishuToolAccount({
2445
- api,
2446
- executeParams: params,
2447
- defaultAccountId
2448
- });
2449
- if (!resolveToolsConfig(account.config.tools).bitable) throw new Error(`Feishu Bitable tools are disabled for account "${account.accountId}"`);
2450
- return createFeishuClient(account);
2451
- };
2443
+ const getClient = (params, defaultAccountId) => createFeishuToolClient({
2444
+ api,
2445
+ executeParams: params,
2446
+ defaultAccountId,
2447
+ requiredTool: {
2448
+ family: "bitable",
2449
+ label: "Bitable"
2450
+ }
2451
+ });
2452
2452
  const registerBitableTool = (params) => {
2453
2453
  api.registerTool((ctx) => ({
2454
2454
  name: params.name,
@@ -2545,4 +2545,4 @@ function registerFeishuBitableTools(api) {
2545
2545
  });
2546
2546
  }
2547
2547
  //#endregion
2548
- export { buildFeishuConversationId, buildFeishuModelOverrideParentCandidates, createClackPrompter, createFeishuThreadBindingManager, feishuPlugin, feishuSetupAdapter, feishuSetupWizard, getFeishuThreadBindingManager, handleFeishuSubagentDeliveryTarget, handleFeishuSubagentEnded, handleFeishuSubagentSpawning, parseFeishuConversationId, parseFeishuDirectConversationId, parseFeishuTargetId, registerFeishuBitableTools, registerFeishuChatTools, registerFeishuDocTools, registerFeishuDriveTools, registerFeishuPermTools, registerFeishuWikiTools, runFeishuLogin, setFeishuNamedAccountEnabled };
2548
+ export { buildFeishuConversationId, buildFeishuModelOverrideParentCandidates, createClackPrompter, createFeishuThreadBindingManager, feishuPlugin, feishuSetupAdapter, feishuSetupWizard, getFeishuThreadBindingManager, handleFeishuSubagentDeliveryTarget, handleFeishuSubagentEnded, parseFeishuConversationId, parseFeishuDirectConversationId, parseFeishuTargetId, registerFeishuBitableTools, registerFeishuChatTools, registerFeishuDocTools, registerFeishuDriveTools, registerFeishuPermTools, registerFeishuWikiTools, runFeishuLogin, setFeishuNamedAccountEnabled };
@@ -9,13 +9,14 @@ import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared
9
9
  import { t as resolveFeishuSessionConversation } from "./session-conversation-DFCIvQK-.js";
10
10
  import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
11
11
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
12
+ import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
12
13
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
13
14
  import { ToolAuthorizationError, createActionGate } from "openclaw/plugin-sdk/channel-actions";
14
15
  import { adaptScopedAccountAccessor, createHybridChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
15
16
  import { buildChannelOutboundSessionRoute, createChatChannelPlugin, stripChannelTargetPrefix } from "openclaw/plugin-sdk/channel-core";
16
17
  import { createAccountStatusSink, createRuntimeOutboundDelegates, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
17
18
  import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
18
- import { createAllowlistProviderGroupPolicyWarningCollector, projectConfigAccountIdWarningCollector } from "openclaw/plugin-sdk/channel-policy";
19
+ import { createAllowlistProviderGroupPolicyWarningCollector, createConditionalWarningCollector } from "openclaw/plugin-sdk/channel-policy";
19
20
  import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime";
20
21
  import { applyDirectoryQueryAndLimit, createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter, listDirectoryGroupEntriesFromMapKeysAndAllowFrom, listDirectoryUserEntriesFromAllowFrom, listDirectoryUserEntriesFromAllowFromAndMapKeys } from "openclaw/plugin-sdk/directory-runtime";
21
22
  import { PlatformMessageNotDispatchedError } from "openclaw/plugin-sdk/error-runtime";
@@ -34,6 +35,7 @@ import { buildSecretInputSchema, hasConfiguredSecretInput as hasConfiguredSecret
34
35
  import fs from "node:fs";
35
36
  import os from "node:os";
36
37
  import path from "node:path";
38
+ import { isPathStrictlyInside } from "openclaw/plugin-sdk/file-access-runtime";
37
39
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
38
40
  import { deleteSessionEntry, isValidAgentHarnessSessionStoreEntry, listSessionEntries, loadTranscriptEventsSync, resolveSessionStoreBackupPaths, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
39
41
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
@@ -430,12 +432,6 @@ function safeReadDir(dir) {
430
432
  return [];
431
433
  }
432
434
  }
433
- function isPathWithinRoot(targetPath, rootPath) {
434
- const resolvedTarget = path.resolve(targetPath);
435
- const resolvedRoot = path.resolve(rootPath);
436
- const relative = path.relative(resolvedRoot, resolvedTarget);
437
- return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
438
- }
439
435
  function formatDisplayPath(filePath) {
440
436
  const home = os.homedir();
441
437
  const resolved = path.resolve(filePath);
@@ -546,8 +542,8 @@ function resolveSessionTranscriptCandidates(params) {
546
542
  const agentSessionsDir = resolveFeishuAgentSessionsDir(params.agentId);
547
543
  const addSafeCandidate = (candidate) => {
548
544
  const resolved = path.isAbsolute(candidate) ? path.resolve(candidate) : path.resolve(sessionsDir, candidate);
549
- const isStoreCandidate = isPathWithinRoot(resolved, sessionsDir);
550
- const isAgentSessionCandidate = isPathWithinRoot(resolved, agentSessionsDir);
545
+ const isStoreCandidate = isPathStrictlyInside(sessionsDir, resolved);
546
+ const isAgentSessionCandidate = isPathStrictlyInside(agentSessionsDir, resolved);
551
547
  if (resolved === sessionsDir || resolved === agentSessionsDir || !isStoreCandidate && !isAgentSessionCandidate) return false;
552
548
  candidates.add(resolved);
553
549
  return true;
@@ -1638,7 +1634,7 @@ const meta = {
1638
1634
  order: 70,
1639
1635
  preferSessionLookupForAnnounceTarget: true
1640
1636
  };
1641
- const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-CoPaHQQ6.js"), "feishuChannelRuntime");
1637
+ const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-DnRyzGoU.js"), "feishuChannelRuntime");
1642
1638
  async function resolveFeishuMessageSender(params) {
1643
1639
  try {
1644
1640
  const sender = params.resolve(await loadFeishuChannelRuntime());
@@ -1732,6 +1728,12 @@ const collectFeishuSecurityWarnings = createAllowlistProviderGroupPolicyWarningC
1732
1728
  }).accountId}] groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.feishu.groupPolicy="allowlist" + channels.feishu.groupAllowFrom to restrict senders.`];
1733
1729
  }
1734
1730
  });
1731
+ const collectFeishuOpenGroupFindings = createConditionalWarningCollector.findings({
1732
+ collectWarnings: collectFeishuSecurityWarnings,
1733
+ checkId: "channels.feishu.groups.open",
1734
+ severity: "critical",
1735
+ title: "Feishu security warning"
1736
+ });
1735
1737
  function describeFeishuMessageTool({ cfg, accountId }) {
1736
1738
  const enabledAccounts = accountId ? [resolveFeishuAccount({
1737
1739
  cfg,
@@ -1907,8 +1909,7 @@ function resolveFeishuMessageActionResponsePrefix(ctx) {
1907
1909
  const channel = ctx.cfg.channels?.feishu;
1908
1910
  const configured = (ctx.accountId ? channel?.accounts?.[ctx.accountId]?.responsePrefix : void 0) ?? channel?.responsePrefix ?? (channel === void 0 ? ctx.cfg.messages?.responsePrefix : void 0);
1909
1911
  if (!configured) return;
1910
- const agentId = (ctx.agentId?.trim() || "main").toLowerCase();
1911
- const identityName = ctx.cfg.agents?.list?.find((agent) => agent.id.trim().toLowerCase() === agentId)?.identity?.name?.trim();
1912
+ const identityName = resolveAgentConfig(ctx.cfg, ctx.agentId ?? "main")?.identity?.name?.trim();
1912
1913
  const resolved = configured === "auto" ? identityName ? `[${identityName}]` : void 0 : configured.replace(/\{(?:identity\.name|identityname)\}/gi, identityName ?? "$&");
1913
1914
  return resolved && !UNRESOLVED_RESPONSE_PREFIX_VAR_PATTERN.test(resolved) ? resolved : void 0;
1914
1915
  }
@@ -2112,6 +2113,7 @@ const feishuPlugin = createChatChannelPlugin({
2112
2113
  ] },
2113
2114
  groups: { resolveToolPolicy: resolveFeishuGroupToolPolicy },
2114
2115
  conversationBindings: {
2116
+ bindingStore: "adapter",
2115
2117
  defaultTopLevelPlacement: "current",
2116
2118
  buildModelOverrideParentCandidates: ({ parentConversationId }) => buildFeishuModelOverrideParentCandidates(parentConversationId)
2117
2119
  },
@@ -2160,6 +2162,7 @@ const feishuPlugin = createChatChannelPlugin({
2160
2162
  collectRuntimeConfigAssignments
2161
2163
  },
2162
2164
  actions: {
2165
+ providerOwnedReadGates: true,
2163
2166
  messageActionTargetAliases,
2164
2167
  describeMessageTool: describeFeishuMessageTool,
2165
2168
  handleAction: async (ctx) => {
@@ -2721,7 +2724,7 @@ const feishuPlugin = createChatChannelPlugin({
2721
2724
  })
2722
2725
  }),
2723
2726
  gateway: { startAccount: async (ctx) => {
2724
- const { monitorFeishuProvider } = await import("./monitor-CeHCfROt.js");
2727
+ const { monitorFeishuProvider } = await import("./monitor-CZ8cDXrq.js");
2725
2728
  const account = resolveFeishuRuntimeAccount({
2726
2729
  cfg: ctx.cfg,
2727
2730
  accountId: ctx.accountId
@@ -2748,7 +2751,10 @@ const feishuPlugin = createChatChannelPlugin({
2748
2751
  message: feishuMessageAdapter
2749
2752
  },
2750
2753
  security: {
2751
- collectWarnings: projectConfigAccountIdWarningCollector(collectFeishuSecurityWarnings),
2754
+ collectWarnings: ({ cfg, accountId }) => collectFeishuOpenGroupFindings({
2755
+ cfg,
2756
+ accountId
2757
+ }),
2752
2758
  collectAuditFindings: ({ cfg }) => collectFeishuSecurityAuditFindings({ cfg })
2753
2759
  },
2754
2760
  pairing: { text: {
@@ -1,2 +1,2 @@
1
- import { t as feishuPlugin } from "./channel-Dzb5jv3i.js";
1
+ import { t as feishuPlugin } from "./channel-Ceq80_zP.js";
2
2
  export { feishuPlugin };
@@ -1,9 +1,9 @@
1
1
  import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount } from "./accounts-CCCdMen2.js";
2
- import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-Dzb5jv3i.js";
2
+ import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-Ceq80_zP.js";
3
3
  import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-DEAycmOk.js";
4
4
  import { r as createFeishuClient } from "./client-Hp7uo_cl.js";
5
- import { _ as parseFeishuCommentTarget, a as assertFeishuChatMember, c as getChatMembers, l as getFeishuMemberInfo, o as buildFeishuDirectChatMembers, r as cleanupAmbientCommentTypingReaction, s as getChatInfo, t as deliverCommentThreadText } from "./drive-B0JkoiRj.js";
6
- import { a as getMessageFeishu, b as resolveFeishuIdentityHeaderTitle, c as sendMarkdownCardFeishu, i as editMessageFeishu, l as sendMessageFeishu, n as sendMediaFeishu, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, u as sendStructuredCardFeishu, v as buildFeishuMediaFallbackText } from "./media-BjSy8fiy.js";
5
+ import { _ as parseFeishuCommentTarget, a as assertFeishuChatMember, c as getChatMembers, l as getFeishuMemberInfo, o as buildFeishuDirectChatMembers, r as cleanupAmbientCommentTypingReaction, s as getChatInfo, t as deliverCommentThreadText } from "./drive-BVYM_Y4k.js";
6
+ import { a as getMessageFeishu, b as resolveFeishuIdentityHeaderTitle, c as sendMarkdownCardFeishu, i as editMessageFeishu, l as sendMessageFeishu, n as sendMediaFeishu, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, u as sendStructuredCardFeishu, v as buildFeishuMediaFallbackText } from "./media-BDouVaaM.js";
7
7
  import { t as probeFeishu } from "./probe-DVpy58s0.js";
8
8
  import { createReplyToFanout } from "openclaw/plugin-sdk/channel-outbound";
9
9
  import { legacyInteractiveReplyToPresentation, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
@@ -143,8 +143,18 @@ function readNativeFeishuCard(payload) {
143
143
  const sanitizedCard = sanitizeNativeFeishuCard(card);
144
144
  return sanitizedCard ? markRenderedFeishuCard(sanitizedCard) : void 0;
145
145
  }
146
+ function toFeishuOutboundResult(result) {
147
+ const { chatId, ...delivery } = result;
148
+ return {
149
+ ...delivery,
150
+ target: {
151
+ kind: "chat",
152
+ id: chatId
153
+ }
154
+ };
155
+ }
146
156
  async function reportFeishuOutboundDelivery(result, onDeliveryResult) {
147
- await onDeliveryResult?.(attachChannelToResult("feishu", result));
157
+ await onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(result)));
148
158
  return result;
149
159
  }
150
160
  function consumeFeishuPresentationFallbackMarker(payload) {
@@ -518,14 +528,14 @@ const feishuOutbound = {
518
528
  replyToId,
519
529
  threadId: ctx.threadId
520
530
  });
521
- return attachChannelToResult("feishu", await sendCardFeishu({
531
+ return attachChannelToResult("feishu", toFeishuOutboundResult(await sendCardFeishu({
522
532
  cfg: ctx.cfg,
523
533
  to: ctx.to,
524
534
  card,
525
535
  replyToMessageId,
526
536
  replyInThread,
527
537
  accountId: ctx.accountId ?? void 0
528
- }));
538
+ })));
529
539
  }
530
540
  });
531
541
  const { normalizedReplyToId } = resolveFeishuReplyMode({
@@ -542,11 +552,11 @@ const feishuOutbound = {
542
552
  threadId: ctx.threadId
543
553
  });
544
554
  const mediaUrls = normalizeStringEntries(resolvePayloadMediaUrls(payload));
545
- return attachChannelToResult("feishu", await sendPayloadMediaSequenceAndFinalize({
555
+ return attachChannelToResult("feishu", toFeishuOutboundResult(await sendPayloadMediaSequenceAndFinalize({
546
556
  text: payload.text ?? "",
547
557
  mediaUrls,
548
558
  onResult: async (deliveryResult) => {
549
- await ctx.onDeliveryResult?.(attachChannelToResult("feishu", deliveryResult));
559
+ await ctx.onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(deliveryResult)));
550
560
  },
551
561
  send: async ({ mediaUrl }) => {
552
562
  const { replyToMessageId, replyInThread } = nextReplyMode();
@@ -574,7 +584,7 @@ const feishuOutbound = {
574
584
  accountId: ctx.accountId ?? void 0
575
585
  });
576
586
  }
577
- }));
587
+ })));
578
588
  },
579
589
  ...createAttachedChannelResultAdapter({
580
590
  channel: "feishu",
@@ -606,7 +616,7 @@ const feishuOutbound = {
606
616
  } catch (err) {
607
617
  if (isChannelPartialDeliveryError(err)) throw err;
608
618
  console.error(`[feishu] local image path auto-send failed:`, err);
609
- return await sendOutboundText({
619
+ return toFeishuOutboundResult(await sendOutboundText({
610
620
  cfg,
611
621
  to,
612
622
  text: await buildFeishuMediaFallbackText({}),
@@ -614,11 +624,11 @@ const feishuOutbound = {
614
624
  replyToMessageId,
615
625
  replyInThread,
616
626
  ...deliveryOptions
617
- });
627
+ }));
618
628
  }
619
- return await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
629
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult));
620
630
  }
621
- if (parseFeishuCommentTarget(to)) return await sendOutboundText({
631
+ if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
622
632
  cfg,
623
633
  to,
624
634
  text,
@@ -626,18 +636,18 @@ const feishuOutbound = {
626
636
  replyToMessageId,
627
637
  replyInThread,
628
638
  ...deliveryOptions
629
- });
639
+ }));
630
640
  const card = readNativeFeishuCardJson(text);
631
641
  if (card) {
632
642
  assertFeishuCardWithinEnvelope(card, "Feishu native card");
633
- return await reportFeishuOutboundDelivery(await sendCardFeishu({
643
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(await sendCardFeishu({
634
644
  cfg,
635
645
  to,
636
646
  card: markRenderedFeishuCard(card),
637
647
  accountId: accountId ?? void 0,
638
648
  replyToMessageId,
639
649
  replyInThread
640
- }), onDeliveryResult);
650
+ }), onDeliveryResult));
641
651
  }
642
652
  const renderMode = resolveFeishuAccount({
643
653
  cfg,
@@ -648,7 +658,7 @@ const feishuOutbound = {
648
658
  title: resolveFeishuIdentityHeaderTitle(identity),
649
659
  template: "blue"
650
660
  } : void 0;
651
- return await reportFeishuOutboundDelivery(await sendStructuredCardFeishu({
661
+ return toFeishuOutboundResult(await reportFeishuOutboundDelivery(await sendStructuredCardFeishu({
652
662
  cfg,
653
663
  to,
654
664
  text,
@@ -656,9 +666,9 @@ const feishuOutbound = {
656
666
  replyInThread,
657
667
  accountId: accountId ?? void 0,
658
668
  header: header?.title ? header : void 0
659
- }), onDeliveryResult);
669
+ }), onDeliveryResult));
660
670
  }
661
- return await sendOutboundText({
671
+ return toFeishuOutboundResult(await sendOutboundText({
662
672
  cfg,
663
673
  to,
664
674
  text,
@@ -666,7 +676,7 @@ const feishuOutbound = {
666
676
  replyToMessageId,
667
677
  replyInThread,
668
678
  ...deliveryOptions
669
- });
679
+ }));
670
680
  },
671
681
  sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, replyToId, replyToIdSource, replyToMode, threadId, onDeliveryResult }) => {
672
682
  const { normalizedReplyToId } = resolveFeishuReplyMode({
@@ -693,7 +703,7 @@ const feishuOutbound = {
693
703
  replyToMode,
694
704
  onDeliveryResult
695
705
  };
696
- if (parseFeishuCommentTarget(to)) return await sendOutboundText({
706
+ if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
697
707
  cfg,
698
708
  to,
699
709
  text: mediaUrl?.trim() ? await buildFeishuMediaFallbackText({
@@ -704,15 +714,15 @@ const feishuOutbound = {
704
714
  accountId: accountId ?? void 0,
705
715
  ...nextReplyMode(),
706
716
  ...deliveryOptions
707
- });
708
- if (!mediaUrl) return await sendOutboundText({
717
+ }));
718
+ if (!mediaUrl) return toFeishuOutboundResult(await sendOutboundText({
709
719
  cfg,
710
720
  to,
711
721
  text: text ?? "",
712
722
  accountId: accountId ?? void 0,
713
723
  ...nextReplyMode(),
714
724
  ...deliveryOptions
715
- });
725
+ }));
716
726
  const suppressTextForVoiceMedia = shouldSuppressFeishuTextForVoiceMedia({
717
727
  mediaUrl,
718
728
  audioAsVoice
@@ -746,7 +756,7 @@ const feishuOutbound = {
746
756
  } catch (err) {
747
757
  if (isChannelPartialDeliveryError(err)) throw err;
748
758
  console.error(`[feishu] sendMediaFeishu failed:`, err);
749
- return await sendOutboundText({
759
+ return toFeishuOutboundResult(await sendOutboundText({
750
760
  cfg,
751
761
  to,
752
762
  text: await buildFeishuMediaFallbackText({
@@ -756,7 +766,7 @@ const feishuOutbound = {
756
766
  accountId: accountId ?? void 0,
757
767
  ...textSent ? nextReplyMode() : mediaReplyMode,
758
768
  ...deliveryOptions
759
- });
769
+ }));
760
770
  }
761
771
  await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
762
772
  if (mediaResult.voiceIntentDegradedToFile && text?.trim()) await sendOutboundText({
@@ -767,7 +777,7 @@ const feishuOutbound = {
767
777
  ...nextReplyMode(),
768
778
  ...deliveryOptions
769
779
  });
770
- return mediaResult;
780
+ return toFeishuOutboundResult(mediaResult);
771
781
  }
772
782
  })
773
783
  };
@@ -58,14 +58,18 @@ function resolveImplicitToolAccountId(params) {
58
58
  }).enabled) return contextualAccountId;
59
59
  }
60
60
  const configuredDefaultAccountId = normalizeOptionalString((params.api.config?.channels?.feishu)?.defaultAccount);
61
- if (configuredDefaultAccountId) return configuredDefaultAccountId;
62
- if (params.requiredTool && params.api.config) for (const accountId of listFeishuAccountIds(params.api.config)) {
61
+ if (configuredDefaultAccountId && resolveFeishuAccount({
62
+ cfg: params.api.config,
63
+ accountId: configuredDefaultAccountId
64
+ }).enabled) return configuredDefaultAccountId;
65
+ if (params.api.config) for (const accountId of listFeishuAccountIds(params.api.config)) {
63
66
  const account = resolveFeishuAccount({
64
67
  cfg: params.api.config,
65
68
  accountId
66
69
  });
67
70
  if (account.enabled && account.configured && resolveToolsConfig(account.config.tools)[params.requiredTool.family]) return accountId;
68
71
  }
72
+ throw new Error(`No usable Feishu account has ${params.requiredTool.label} tools enabled`);
69
73
  }
70
74
  function resolveFeishuToolAccount(params) {
71
75
  if (!params.api.config) throw new Error("Feishu config unavailable");
@@ -73,7 +77,7 @@ function resolveFeishuToolAccount(params) {
73
77
  cfg: params.api.config,
74
78
  accountId: resolveImplicitToolAccountId(params)
75
79
  });
76
- if (params.requiredTool && !resolveToolsConfig(account.config.tools)[params.requiredTool.family]) throw new Error(`Feishu ${params.requiredTool.label} tools are disabled for account "${account.accountId}"`);
80
+ if (!resolveToolsConfig(account.config.tools)[params.requiredTool.family]) throw new Error(`Feishu ${params.requiredTool.label} tools are disabled for account "${account.accountId}"`);
77
81
  return account;
78
82
  }
79
83
  function createFeishuToolClient(params) {
@@ -1349,4 +1353,4 @@ function registerFeishuDriveTools(api) {
1349
1353
  }, { name: "feishu_drive" });
1350
1354
  }
1351
1355
  //#endregion
1352
- export { resolveFeishuToolAccount as C, resolveAnyEnabledFeishuToolsConfig as S, parseFeishuCommentTarget as _, assertFeishuChatMember as a, unknownToolActionResult as b, getChatMembers as c, encodeQuery as d, extractReplyText as f, normalizeCommentFileType as g, buildFeishuCommentTarget as h, createCommentTypingReactionLifecycle as i, getFeishuMemberInfo as l, requestFeishuApi as m, registerFeishuDriveTools as n, buildFeishuDirectChatMembers as o, parseCommentContentElements as p, cleanupAmbientCommentTypingReaction as r, getChatInfo as s, deliverCommentThreadText as t, registerFeishuChatTools as u, feishuExternalToolResult as v, resolveToolsConfig as w, createFeishuToolClient as x, toolExecutionErrorResult as y };
1356
+ export { resolveFeishuToolAccount as C, resolveAnyEnabledFeishuToolsConfig as S, parseFeishuCommentTarget as _, assertFeishuChatMember as a, unknownToolActionResult as b, getChatMembers as c, encodeQuery as d, extractReplyText as f, normalizeCommentFileType as g, buildFeishuCommentTarget as h, createCommentTypingReactionLifecycle as i, getFeishuMemberInfo as l, requestFeishuApi as m, registerFeishuDriveTools as n, buildFeishuDirectChatMembers as o, parseCommentContentElements as p, cleanupAmbientCommentTypingReaction as r, getChatInfo as s, deliverCommentThreadText as t, registerFeishuChatTools as u, feishuExternalToolResult as v, createFeishuToolClient as x, toolExecutionErrorResult as y };
@@ -3,7 +3,7 @@ import { i as resolveReceiveIdType, r as normalizeFeishuTarget } from "./targets
3
3
  import { c as assertFeishuPostWithinEnvelope, f as materializeFeishuPostMarkdownSoftBreaks, i as toFeishuSendResult, l as buildFeishuPostMessageContent, o as resolveFeishuCardTemplate, r as resolveFeishuReceiptKind, t as assertFeishuMessageApiSuccess } from "./send-result-DEAycmOk.js";
4
4
  import { r as createFeishuClient } from "./client-Hp7uo_cl.js";
5
5
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
6
- import { m as requestFeishuApi } from "./drive-B0JkoiRj.js";
6
+ import { m as requestFeishuApi } from "./drive-BVYM_Y4k.js";
7
7
  import { PlatformMessageNotDispatchedError } from "openclaw/plugin-sdk/error-runtime";
8
8
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
9
9
  import { isRecord, normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -2,7 +2,7 @@ import { r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from
2
2
  import { t as fetchBotIdentityForMonitor } from "./monitor.startup-BGErejNH.js";
3
3
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
4
  //#region extensions/feishu/src/monitor.ts
5
- const loadMonitorAccountRuntime = createLazyRuntimeModule(() => import("./monitor.account-DwdqexLU.js"));
5
+ const loadMonitorAccountRuntime = createLazyRuntimeModule(() => import("./monitor.account-Dq_voVMB.js"));
6
6
  async function monitorFeishuProvider(opts = {}) {
7
7
  const cfg = opts.config;
8
8
  if (!cfg) throw new Error("Config is required for Feishu monitor");
@@ -5,13 +5,14 @@ import { i as normalizeFeishuWebhookPath } from "./doctor-contract-bEQXIXyP.js";
5
5
  import { o as resolveConfiguredFeishuGroupSessionScope, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
6
6
  import { a as getFeishuUserAgent, i as createFeishuWSClient, n as createEventDispatcher, r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-Hp7uo_cl.js";
7
7
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
8
- import { d as encodeQuery, f as extractReplyText, g as normalizeCommentFileType, h as buildFeishuCommentTarget, i as createCommentTypingReactionLifecycle, m as requestFeishuApi, p as parseCommentContentElements, s as getChatInfo, t as deliverCommentThreadText } from "./drive-B0JkoiRj.js";
9
- import { t as createFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
8
+ import { d as encodeQuery, f as extractReplyText, g as normalizeCommentFileType, h as buildFeishuCommentTarget, i as createCommentTypingReactionLifecycle, m as requestFeishuApi, p as parseCommentContentElements, s as getChatInfo, t as deliverCommentThreadText } from "./drive-BVYM_Y4k.js";
9
+ import { t as createFeishuThreadBindingManager } from "./thread-bindings-CptM_YU6.js";
10
10
  import { createReplyPrefixContext, evaluateSupplementalContextVisibility, getSessionEntry, normalizeAgentId as normalizeAgentId$1, resolveChannelContextVisibilityMode } from "./runtime-api.js";
11
11
  import { t as readFeishuJsonResponse } from "./json-response-CheljwGr.js";
12
- import { _ as normalizeFeishuExternalKey, a as getMessageFeishu, d as extractMentionTargets, f as isFeishuBroadcastMention, g as parsePostContent, h as parseInteractiveCardContent, l as sendMessageFeishu, m as isFeishuGroupChatType, n as sendMediaFeishu, o as listFeishuThreadMessages, p as isMentionForwardRequest, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, t as saveMessageResourceFeishu, u as sendStructuredCardFeishu, v as buildFeishuMediaFallbackText, y as resolveFeishuIdentityEmoji } from "./media-BjSy8fiy.js";
12
+ import { _ as normalizeFeishuExternalKey, a as getMessageFeishu, d as extractMentionTargets, f as isFeishuBroadcastMention, g as parsePostContent, h as parseInteractiveCardContent, l as sendMessageFeishu, m as isFeishuGroupChatType, n as sendMediaFeishu, o as listFeishuThreadMessages, p as isMentionForwardRequest, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, t as saveMessageResourceFeishu, u as sendStructuredCardFeishu, v as buildFeishuMediaFallbackText, y as resolveFeishuIdentityEmoji } from "./media-BDouVaaM.js";
13
13
  import { a as waitForAbortableDelay, i as raceWithTimeoutAndAbort } from "./probe-DVpy58s0.js";
14
14
  import { t as fetchBotIdentityForMonitor } from "./monitor.startup-BGErejNH.js";
15
+ import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
15
16
  import { DEFAULT_INGRESS_ADOPTION_STALL_MS, bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, formatChannelProgressDraftLineForEntry, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
16
17
  import { createChannelPairingController, createChannelPairingController as createChannelPairingController$1 } from "openclaw/plugin-sdk/channel-pairing";
17
18
  import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
@@ -24,10 +25,10 @@ import { fanInChannelIngressLifecycles } from "openclaw/plugin-sdk/channel-ingre
24
25
  import fs from "node:fs";
25
26
  import os from "node:os";
26
27
  import path from "node:path";
27
- import { normalizeAccountId, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
28
+ import { normalizeAccountId, resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
28
29
  import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
29
30
  import { isRecord as isRecord$1 } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
30
- import { createChannelPartialDeliveryError, formatAgentEnvelope, formatInboundMediaUnavailableText, isChannelPartialDeliveryError, recordChannelBotPairLoopAndCheckSuppression, resolveEnvelopeFormatOptions, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
31
+ import { createChannelPartialDeliveryError, formatAgentEnvelope, formatInboundMediaUnavailableText, isChannelPartialDeliveryError, recordChannelBotPairLoopAndCheckSuppression, resolveEnvelopeFormatOptions, resolveInboundReplyDispatchCounts, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
31
32
  import * as Lark from "@larksuiteoapi/node-sdk";
32
33
  import { resolvePinnedMainDmOwnerFromAllowlist, safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
33
34
  import { WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, applyBasicWebhookRequestGuards, createFixedWindowRateLimiter, createWebhookAnomalyTracker, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
@@ -1139,8 +1140,7 @@ function resolveUserPath(p) {
1139
1140
  //#endregion
1140
1141
  //#region extensions/feishu/src/agent-config.ts
1141
1142
  function resolveFeishuConfigReasoningDefault(cfg, agentId) {
1142
- const id = normalizeAgentId(agentId);
1143
- return cfg.agents?.list?.find((entry) => normalizeAgentId(entry?.id) === id)?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault ?? "off";
1143
+ return resolveAgentConfig(cfg, agentId)?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault ?? "off";
1144
1144
  }
1145
1145
  //#endregion
1146
1146
  //#region extensions/feishu/src/reasoning-preview.ts
@@ -1186,10 +1186,11 @@ function createFeishuReplyDeliveryResult(params) {
1186
1186
  /** Preserves the first result's provider identity while retaining supplemental ids. */
1187
1187
  function mergeFeishuReplyDeliveryResults(results, content) {
1188
1188
  const visible = results.filter((result) => result.visibleReplySent === true);
1189
+ const acceptedContent = visible.flatMap((result) => result.content === void 0 ? [] : [result.content]);
1189
1190
  return createFeishuReplyDeliveryResult({
1190
1191
  results: visible,
1191
1192
  visibleReplySent: visible.length > 0,
1192
- content: content === void 0 ? results.find((result) => result.content !== void 0)?.content : content
1193
+ content: content === void 0 ? acceptedContent.length > 0 ? acceptedContent.join("\n\n") : void 0 : content
1193
1194
  });
1194
1195
  }
1195
1196
  /** Keeps a failed outcome while exposing the provider-visible subset to core lifecycle hooks. */
@@ -2231,13 +2232,20 @@ function createFeishuReplyDispatcher(params) {
2231
2232
  acceptedChunks.push(chunk);
2232
2233
  markVisibleReplySent();
2233
2234
  } catch (error) {
2234
- if (isChannelPartialDeliveryError(error)) markVisibleReplySent();
2235
- throw createFeishuPartialReplyDeliveryError(error, createFeishuReplyDeliveryResult({
2236
- results,
2237
- visibleReplySent: results.length > 0,
2238
- content: acceptedChunks.join(""),
2239
- kind: paramsLocal.useCard ? "card" : "text"
2240
- }));
2235
+ const acceptedChunk = isChannelPartialDeliveryError(error) ? error.deliveryResult : void 0;
2236
+ if (acceptedChunk) {
2237
+ acceptedChunks.push(acceptedChunk.content ?? chunk);
2238
+ markVisibleReplySent();
2239
+ }
2240
+ throw createFeishuPartialReplyDeliveryError(error, {
2241
+ ...acceptedChunk,
2242
+ ...createFeishuReplyDeliveryResult({
2243
+ results,
2244
+ visibleReplySent: results.length > 0 || acceptedChunk !== void 0,
2245
+ content: acceptedChunks.join(""),
2246
+ kind: paramsLocal.useCard ? "card" : "text"
2247
+ })
2248
+ });
2241
2249
  }
2242
2250
  }
2243
2251
  if (paramsLocal.infoKind === "final") deliveredFinalTexts.add(paramsLocal.text);
@@ -2662,7 +2670,7 @@ function createFeishuReplyDispatcher(params) {
2662
2670
  }
2663
2671
  }
2664
2672
  if (hasMedia) await collectMediaDelivery(payload, hasVoiceMedia && hasText ? { fallbackText: text } : void 0);
2665
- const result = mergeFeishuReplyDeliveryResults(deliveredResults, text);
2673
+ const result = mergeFeishuReplyDeliveryResults(deliveredResults, hasVoiceMedia ? deliveredResults.at(-1)?.content ?? text : text);
2666
2674
  if (priorClosedStreamingSettlement?.error !== void 0) throw createFeishuPartialReplyDeliveryError(isChannelPartialDeliveryError(priorClosedStreamingSettlement.error) && priorClosedStreamingSettlement.error instanceof Error ? priorClosedStreamingSettlement.error.cause ?? priorClosedStreamingSettlement.error : priorClosedStreamingSettlement.error, result);
2667
2675
  return result;
2668
2676
  },
@@ -2730,11 +2738,9 @@ function getFeishuSyntheticDirectPreDispatchTarget(event) {
2730
2738
  const permissionErrorNotifiedAt = /* @__PURE__ */ new Map();
2731
2739
  const PERMISSION_ERROR_COOLDOWN_MS = 300 * 1e3;
2732
2740
  function shouldSendNoVisibleReplyFallback(dispatchResult) {
2733
- const finalCount = dispatchResult.counts.final ?? 0;
2734
- const failedFinalCount = dispatchResult.failedCounts?.final ?? 0;
2735
- const emptyEligibleDispatch = dispatchResult.noVisibleReplyFallbackEligible === true && dispatchResult.queuedFinal !== true && finalCount === 0;
2736
- const queuedFinalFailed = dispatchResult.queuedFinal === true && failedFinalCount > 0;
2737
- return dispatchResult.sendPolicyDenied !== true && dispatchResult.sourceReplyDeliveryMode !== "message_tool_only" && (emptyEligibleDispatch || queuedFinalFailed);
2741
+ const emptyEligibleDispatch = dispatchResult.noVisibleReplyFallbackEligible === true && dispatchResult.settledReceipt?.anyVisibleDelivered !== true;
2742
+ const finalFailedBeforeSend = (dispatchResult.settledReceipt?.counts.final.failedBeforeSend ?? 0) > 0;
2743
+ return dispatchResult.sendPolicyDenied !== true && dispatchResult.sourceReplyDeliveryMode !== "message_tool_only" && (emptyEligibleDispatch || finalFailedBeforeSend);
2738
2744
  }
2739
2745
  function isFeishuTopicSessionScope(scope) {
2740
2746
  return scope === "group_topic" || scope === "group_topic_sender";
@@ -3601,7 +3607,12 @@ async function handleFeishuMessage(params) {
3601
3607
  conversation: {
3602
3608
  kind: isGroup ? "group" : "direct",
3603
3609
  id: ctx.chatId,
3610
+ routePeer: {
3611
+ kind: isGroup ? "group" : "direct",
3612
+ id: peerId
3613
+ },
3604
3614
  nativeChannelId: ctx.chatId,
3615
+ parentId: parentPeer?.id,
3605
3616
  label: isGroup && groupName && !isTopicSessionForThread ? groupName : void 0,
3606
3617
  threadId: ctx.rootId && isTopicSessionForThread ? ctx.rootId : void 0
3607
3618
  },
@@ -5603,7 +5614,7 @@ function buildDriveCommentSurfacePrompt(params) {
5603
5614
  if (params.nearestBotWholeCommentBefore) lines.push(`Nearest bot-authored whole-comment before the current comment: comment_id=${params.nearestBotWholeCommentBefore.commentId} text=${formatPromptTextValue(params.nearestBotWholeCommentBefore.content.semanticText ?? params.nearestBotWholeCommentBefore.content.plainText)}`);
5604
5615
  lines.push("For this whole-document comment, use the whole-comment timeline above as the primary source for phrases like 'just now', 'previous result', 'that summary', or 'write it back'.", "Document-level session history is auxiliary background only. Do not resolve whole-comment follow-ups by blindly using the most recent document-session output.");
5605
5616
  }
5606
- lines.push("This is a Feishu document comment thread.", "It is not a Feishu IM chat.", "Your final text reply will be posted to the current comment thread automatically.", "Use the thread timeline above as the main context for follow-up requests.", "Do not use another comment card or document-session output as the main reference.", "If you need comment thread context, use feishu_drive.list_comments or feishu_drive.list_comment_replies.", "If you modify the document, post a user-visible follow-up in the comment thread.", "Use feishu_drive.reply_comment or feishu_drive.add_comment for that follow-up.", "Whole-document comments do not support direct replies.", "For whole-document comments, use feishu_drive.add_comment.", "Only treat URLs listed under \"Referenced documents from current user comment\" as structured Feishu document references.", "URLs that appear only in comment text are plain links unless you verify them.", "If the user asks about a linked Feishu document or wiki page, treat that linked document as the read target.", "If the user asks you to use a linked document as guidance, treat the linked document as the reference source and the current commented document as the edit target.", "If a referenced document resolves to the same file_token and file_type as the current commented document, treat it as the current document.", "If the user asks you to modify document content, you must use feishu_doc to make the change.", "Do not reply with only \"done\", \"I'll handle it\", or a restated plan without calling tools.", "If the comment quotes document content, treat the quoted content as the main anchor.", "For requests like \"insert xxx below this content\", locate the quoted content first, then edit the document.", "For requests like \"summarize the content below\", \"explain this section\", or \"continue writing from here\", use the quoted content as the main target.", "If the quote is not enough, use feishu_doc.read or feishu_doc.list_blocks to read nearby context.", "Do not guess document content from the comment alone.", "Do not give a vague answer before reading enough context.", "Unless the user asks for the whole document, handle only the local content around the quoted anchor.", "If document edits are involved, read the anchor first, then edit.", "If the edit fails or the anchor cannot be found, say so clearly.", "If this is a reading task, such as summarization, explanation, or extraction, you may output the final answer directly after confirming the context.", "Use the same language as the user's comment or reply, unless the user asks for another language.", "Use plain text only.", "Do not use Markdown.", "Do not use headings.", "Do not use bullet lists.", "Do not use numbered lists.", "Do not use tables.", "Do not use blockquotes.", "Do not use code blocks.", "Do not show reasoning.", "Do not show analysis.", "Do not show chain-of-thought.", "Do not show scratch work.", "Do not describe your plan.", "Do not describe your steps.", "Do not describe tool use.", "Do not start with phrases like \"I will\", \"I’ll first\", \"I need to\", \"The user wants\", or \"I have updated\".", "Output only the final user-facing reply.", "If you already sent the user-visible reply with feishu_drive.reply_comment or feishu_drive.add_comment, output exactly NO_REPLY.", "If no user-visible reply is needed, output exactly NO_REPLY.", "Be concise.", "Do not omit requested content.");
5617
+ lines.push("This is a Feishu document comment thread.", "It is not a Feishu IM chat.", "Your final text reply will be posted to the current comment thread automatically.", "Use the thread timeline above as the main context for follow-up requests.", "Do not use another comment card or document-session output as the main reference.", "If you need comment thread context, use the available Feishu drive comment-list actions.", "If you modify the document, post a user-visible follow-up in the comment thread.", "Use an available Feishu drive reply-comment or add-comment action for that follow-up.", "Whole-document comments do not support direct replies.", "For whole-document comments, use the Feishu drive add-comment action when available.", "Only treat URLs listed under \"Referenced documents from current user comment\" as structured Feishu document references.", "URLs that appear only in comment text are plain links unless you verify them.", "If the user asks about a linked Feishu document or wiki page, treat that linked document as the read target.", "If the user asks you to use a linked document as guidance, treat the linked document as the reference source and the current commented document as the edit target.", "If a referenced document resolves to the same file_token and file_type as the current commented document, treat it as the current document.", "If the user asks you to modify document content, you must use an available Feishu document tool to make the change.", "Do not reply with only \"done\", \"I'll handle it\", or a restated plan without calling tools.", "If the comment quotes document content, treat the quoted content as the main anchor.", "For requests like \"insert xxx below this content\", locate the quoted content first, then edit the document.", "For requests like \"summarize the content below\", \"explain this section\", or \"continue writing from here\", use the quoted content as the main target.", "If the quote is not enough, use available Feishu document read or list-blocks actions to read nearby context.", "Do not guess document content from the comment alone.", "Do not give a vague answer before reading enough context.", "Unless the user asks for the whole document, handle only the local content around the quoted anchor.", "If document edits are involved, read the anchor first, then edit.", "If the edit fails or the anchor cannot be found, say so clearly.", "If this is a reading task, such as summarization, explanation, or extraction, you may output the final answer directly after confirming the context.", "Use the same language as the user's comment or reply, unless the user asks for another language.", "Use plain text only.", "Do not use Markdown.", "Do not use headings.", "Do not use bullet lists.", "Do not use numbered lists.", "Do not use tables.", "Do not use blockquotes.", "Do not use code blocks.", "Do not show reasoning.", "Do not show analysis.", "Do not show chain-of-thought.", "Do not show scratch work.", "Do not describe your plan.", "Do not describe your steps.", "Do not describe tool use.", "Do not start with phrases like \"I will\", \"I’ll first\", \"I need to\", \"The user wants\", or \"I have updated\".", "Output only the final user-facing reply.", "If you already sent the user-visible reply with a Feishu drive comment action, output exactly NO_REPLY.", "If no user-visible reply is needed, output exactly NO_REPLY.", "Be concise.", "Do not omit requested content.");
5607
5618
  lines.push("Choose one outcome: output the final plain-text reply, edit the document and then post a user-visible follow-up in the comment thread, or output exactly NO_REPLY.");
5608
5619
  return lines.join("\n");
5609
5620
  }
@@ -5997,14 +6008,8 @@ async function handleFeishuCommentEvent(params) {
5997
6008
  })
5998
6009
  }
5999
6010
  });
6000
- const dispatchResult = turnResult.dispatched ? turnResult.dispatchResult : void 0;
6001
- const queuedFinal = dispatchResult?.queuedFinal ?? false;
6002
- const counts = dispatchResult?.counts ?? {
6003
- tool: 0,
6004
- block: 0,
6005
- final: 0
6006
- };
6007
- log(`feishu[${account.accountId}]: drive comment dispatch complete (queuedFinal=${queuedFinal}, replies=${counts.final}, session=${commentSessionKey})`);
6011
+ const counts = resolveInboundReplyDispatchCounts(turnResult.dispatched ? turnResult.dispatchResult : void 0);
6012
+ log(`feishu[${account.accountId}]: drive comment dispatch complete (replies=${counts.final}, session=${commentSessionKey})`);
6008
6013
  } finally {
6009
6014
  cleanupTypingReaction();
6010
6015
  }
@@ -1,2 +1,2 @@
1
- import { r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
2
- export { createFeishuThreadBindingManager, testing as feishuThreadBindingTesting };
1
+ import { t as createFeishuThreadBindingManager } from "./thread-bindings-CptM_YU6.js";
2
+ export { createFeishuThreadBindingManager };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-Dzb5jv3i.js";
1
+ import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-Ceq80_zP.js";
2
2
  export { feishuPlugin, feishuSetupAdapter, feishuSetupWizard };
@@ -1,19 +1,13 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { r as normalizeFeishuTarget } from "./targets-BUjQ1TcA.js";
3
3
  import { r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-VYgGQ-GX.js";
4
- import { n as getFeishuThreadBindingManager } from "./thread-bindings-Itvfmx6_.js";
4
+ import { n as getFeishuThreadBindingManager } from "./thread-bindings-CptM_YU6.js";
5
5
  import { normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  //#region extensions/feishu/src/subagent-hooks.ts
7
7
  var subagent_hooks_exports = /* @__PURE__ */ __exportAll({
8
8
  handleFeishuSubagentDeliveryTarget: () => handleFeishuSubagentDeliveryTarget,
9
- handleFeishuSubagentEnded: () => handleFeishuSubagentEnded,
10
- handleFeishuSubagentSpawning: () => handleFeishuSubagentSpawning
9
+ handleFeishuSubagentEnded: () => handleFeishuSubagentEnded
11
10
  });
12
- function summarizeError(err) {
13
- if (err instanceof Error) return err.message;
14
- if (typeof err === "string") return err;
15
- return "error";
16
- }
17
11
  function stripProviderPrefix(raw) {
18
12
  return raw.replace(/^(feishu|lark):/i, "").trim();
19
13
  }
@@ -157,60 +151,6 @@ function resolveMatchingChildBinding(params) {
157
151
  }
158
152
  return childBindings.length === 1 ? childBindings[0] : null;
159
153
  }
160
- async function handleFeishuSubagentSpawning(event, ctx) {
161
- if (!event.threadRequested) return;
162
- if (normalizeOptionalLowercaseString(event.requester?.channel) !== "feishu") return;
163
- const manager = getFeishuThreadBindingManager(event.requester?.accountId);
164
- if (!manager) return {
165
- status: "error",
166
- error: "Feishu current-conversation binding is unavailable because the Feishu account monitor is not active."
167
- };
168
- const conversation = resolveFeishuRequesterConversation({
169
- accountId: event.requester?.accountId,
170
- to: event.requester?.to,
171
- threadId: event.requester?.threadId,
172
- requesterSessionKey: ctx.requesterSessionKey
173
- });
174
- if (!conversation) return {
175
- status: "error",
176
- error: "Feishu current-conversation binding is only available in direct messages or topic conversations."
177
- };
178
- try {
179
- const binding = manager.bindConversation({
180
- conversationId: conversation.conversationId,
181
- parentConversationId: conversation.parentConversationId,
182
- targetKind: "subagent",
183
- targetSessionKey: event.childSessionKey,
184
- metadata: {
185
- agentId: event.agentId,
186
- label: event.label,
187
- boundBy: "system",
188
- deliveryTo: event.requester?.to,
189
- deliveryThreadId: event.requester?.threadId != null && event.requester.threadId !== "" ? String(event.requester.threadId) : void 0
190
- }
191
- });
192
- if (!binding) return {
193
- status: "error",
194
- error: "Unable to bind this Feishu conversation to the spawned subagent session. Session mode is unavailable for this target."
195
- };
196
- return {
197
- status: "ok",
198
- threadBindingReady: true,
199
- deliveryOrigin: resolveFeishuDeliveryOrigin({
200
- conversationId: binding.conversationId,
201
- parentConversationId: binding.parentConversationId,
202
- accountId: binding.accountId,
203
- deliveryTo: binding.deliveryTo,
204
- deliveryThreadId: binding.deliveryThreadId
205
- })
206
- };
207
- } catch (err) {
208
- return {
209
- status: "error",
210
- error: `Feishu conversation bind failed: ${summarizeError(err)}`
211
- };
212
- }
213
- }
214
154
  function handleFeishuSubagentDeliveryTarget(event) {
215
155
  if (!event.expectsCompletionMessage) return;
216
156
  if (normalizeOptionalLowercaseString(event.requesterOrigin?.channel) !== "feishu") return;
@@ -236,4 +176,4 @@ function handleFeishuSubagentEnded(event) {
236
176
  getFeishuThreadBindingManager(event.accountId)?.unbindBySessionKey(event.targetSessionKey);
237
177
  }
238
178
  //#endregion
239
- export { subagent_hooks_exports as i, handleFeishuSubagentEnded as n, handleFeishuSubagentSpawning as r, handleFeishuSubagentDeliveryTarget as t };
179
+ export { handleFeishuSubagentEnded as n, subagent_hooks_exports as r, handleFeishuSubagentDeliveryTarget as t };
@@ -1,6 +1,6 @@
1
1
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2
2
  //#region extensions/feishu/subagent-hooks-api.ts
3
- const loadFeishuSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-B867acTt.js").then((n) => n.i));
3
+ const loadFeishuSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-KUi-7vUy.js").then((n) => n.r));
4
4
  function registerFeishuSubagentHooks(api) {
5
5
  api.on("subagent_delivery_target", async (event) => {
6
6
  const { handleFeishuSubagentDeliveryTarget } = await loadFeishuSubagentHooksModule();
@@ -1,8 +1,8 @@
1
+ import { resolveSessionAgentId } from "openclaw/plugin-sdk/agent-scope-runtime";
1
2
  import { registerSessionBindingAdapter, resolveThreadBindingConversationIdFromBindingId, resolveThreadBindingIdleTimeoutMsForChannel, resolveThreadBindingMaxAgeMsForChannel, unregisterSessionBindingAdapter } from "openclaw/plugin-sdk/conversation-runtime";
2
3
  import { isFutureDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
3
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
5
- import { resolveSessionAgentId } from "openclaw/plugin-sdk/agent-scope-runtime";
6
6
  //#region extensions/feishu/src/thread-bindings.ts
7
7
  const FEISHU_THREAD_BINDINGS_STATE_KEY = Symbol.for("openclaw.feishuThreadBindingsState");
8
8
  let state;
@@ -214,10 +214,5 @@ function createFeishuThreadBindingManager(params) {
214
214
  function getFeishuThreadBindingManager(accountId) {
215
215
  return getState().managersByAccountId.get(normalizeAccountId(accountId)) ?? null;
216
216
  }
217
- const testing = { resetFeishuThreadBindingsForTests() {
218
- for (const manager of getState().managersByAccountId.values()) manager.stop();
219
- getState().managersByAccountId.clear();
220
- getState().bindingsByAccountConversation.clear();
221
- } };
222
217
  //#endregion
223
- export { getFeishuThreadBindingManager as n, testing as r, createFeishuThreadBindingManager as t };
218
+ export { getFeishuThreadBindingManager as n, createFeishuThreadBindingManager as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/feishu",
3
- "version": "2026.8.1-beta.2",
3
+ "version": "2026.8.1-beta.3",
4
4
  "description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "zod": "4.4.3"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.8.1-beta.2"
19
+ "openclaw": ">=2026.8.1-beta.3"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -60,10 +60,10 @@
60
60
  "minHostVersion": ">=2026.5.29"
61
61
  },
62
62
  "compat": {
63
- "pluginApi": ">=2026.8.1-beta.2"
63
+ "pluginApi": ">=2026.8.1-beta.3"
64
64
  },
65
65
  "build": {
66
- "openclawVersion": "2026.8.1-beta.2"
66
+ "openclawVersion": "2026.8.1-beta.3"
67
67
  },
68
68
  "release": {
69
69
  "publishToClawHub": true,