@openclaw/feishu 2026.6.11 → 2026.7.1-beta.2
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 +1 -1
- package/dist/{app-registration-tgQJUcv3.js → app-registration-DuEyfVY1.js} +2 -6
- package/dist/{channel-C1MthXp0.js → channel-Bwm5rvHg.js} +27 -29
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-CiQqumBC.js → channel.runtime-C6SITclp.js} +36 -26
- package/dist/{monitor-CxUQtU--.js → monitor-Ckch4qvr.js} +7 -8
- package/dist/{monitor.account-C3SH96dD.js → monitor.account-GXGIJrgw.js} +116 -37
- package/dist/{monitor.state-CGL1occz.js → monitor.state-R4ZgNpac.js} +1 -1
- package/dist/{probe-EyeJQb3C.js → probe-Cv2M2Ivr.js} +2 -1
- package/dist/runtime-api.js +2 -2
- package/dist/{secret-contract-ChjJKAJ9.js → secret-contract-DLaBl9m4.js} +26 -8
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-B0nDqief.js → send-BJTjDWKi.js} +40 -6
- package/dist/setup-api.js +1 -1
- package/dist/subagent-hooks-api.js +2 -5
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as listEnabledFeishuAccounts } from "./accounts-Cfzht2Hc.js";
|
|
2
|
-
import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-
|
|
2
|
+
import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-Bwm5rvHg.js";
|
|
3
3
|
import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-DuL575sn.js";
|
|
4
4
|
import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
|
|
5
5
|
import { r as createFeishuClient } from "./client-BwgAJuvo.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
2
|
+
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
|
2
3
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
3
4
|
import { renderQrTerminal } from "openclaw/plugin-sdk/media-runtime";
|
|
4
5
|
//#region extensions/feishu/src/app-registration.ts
|
|
@@ -135,7 +136,7 @@ async function pollAppRegistration(params) {
|
|
|
135
136
|
* otherwise the pattern is corrupted and cannot be scanned.
|
|
136
137
|
*/
|
|
137
138
|
async function printQrCode(url) {
|
|
138
|
-
const output = await renderQrTerminal(url);
|
|
139
|
+
const output = await renderQrTerminal(url, { small: true });
|
|
139
140
|
process.stdout.write(output.endsWith("\n") ? output : `${output}\n`);
|
|
140
141
|
}
|
|
141
142
|
/**
|
|
@@ -181,11 +182,6 @@ async function getAppOwnerOpenId(params) {
|
|
|
181
182
|
return;
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
|
-
function sleep(ms) {
|
|
185
|
-
return new Promise((resolve) => {
|
|
186
|
-
setTimeout(resolve, ms);
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
185
|
function sleepRegistrationPollInterval(intervalSeconds) {
|
|
190
186
|
return sleep(finiteSecondsToTimerSafeMilliseconds(intervalSeconds) ?? finiteSecondsToTimerSafeMilliseconds(DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS) ?? REQUEST_TIMEOUT_MS);
|
|
191
187
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { a as resolveDefaultFeishuAccountId, d as isRecord$
|
|
1
|
+
import { a as resolveDefaultFeishuAccountId, d as isRecord$1, i as listFeishuAccountIds, n as inspectFeishuCredentials, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-Cfzht2Hc.js";
|
|
2
2
|
import { n as looksLikeFeishuId, r as normalizeFeishuTarget, t as detectIdType } from "./targets-BUjQ1TcA.js";
|
|
3
3
|
import { n as createFeishuSendReceipt, s as createFeishuCardInteractionEnvelope } from "./send-result-DSsIa4-p.js";
|
|
4
4
|
import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-DuL575sn.js";
|
|
5
5
|
import { t as messageActionTargetAliases } from "./security-audit-BIeA3W3Q.js";
|
|
6
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
6
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DLaBl9m4.js";
|
|
7
7
|
import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BIHeF-S_.js";
|
|
8
8
|
import { t as resolveFeishuSessionConversation } from "./session-conversation-CZSMgac-.js";
|
|
9
|
+
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
|
9
10
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
10
11
|
import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
|
|
11
12
|
import { adaptScopedAccountAccessor, createHybridChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
12
13
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, stripChannelTargetPrefix } from "openclaw/plugin-sdk/channel-core";
|
|
13
|
-
import { createRuntimeOutboundDelegates, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
14
|
+
import { createAccountStatusSink, createRuntimeOutboundDelegates, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
14
15
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
15
16
|
import { createAllowlistProviderGroupPolicyWarningCollector, projectConfigAccountIdWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
16
17
|
import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime";
|
|
17
18
|
import { createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter, listDirectoryGroupEntriesFromMapKeysAndAllowFrom, listDirectoryUserEntriesFromAllowFromAndMapKeys } from "openclaw/plugin-sdk/directory-runtime";
|
|
18
19
|
import { normalizeMessagePresentation, renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
|
|
19
|
-
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
|
20
20
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
21
21
|
import { buildProbeChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
22
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
22
|
+
import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
23
23
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
24
24
|
import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
25
25
|
import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
|
|
@@ -383,11 +383,8 @@ const SESSION_FILE_INSPECTION_MAX_BYTES = 16 * 1024 * 1024;
|
|
|
383
383
|
function timestampForPath(now = /* @__PURE__ */ new Date()) {
|
|
384
384
|
return now.toISOString().replaceAll(":", "-");
|
|
385
385
|
}
|
|
386
|
-
function isRecord$1(value) {
|
|
387
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
388
|
-
}
|
|
389
386
|
function toFeishuSessionEntry(value) {
|
|
390
|
-
if (!isRecord
|
|
387
|
+
if (!isRecord(value)) return {};
|
|
391
388
|
return {
|
|
392
389
|
sessionId: value.sessionId,
|
|
393
390
|
sessionFile: value.sessionFile
|
|
@@ -450,12 +447,12 @@ function normalizeMetadataString(value) {
|
|
|
450
447
|
function isFeishuSessionEntry(key, value) {
|
|
451
448
|
if (isFeishuAcpBindingSessionKey(key)) return false;
|
|
452
449
|
if (isFeishuSessionStoreKey(key)) return true;
|
|
453
|
-
if (!isRecord
|
|
450
|
+
if (!isRecord(value)) return false;
|
|
454
451
|
if (normalizeMetadataString(value.channel) === "feishu" || normalizeMetadataString(value.lastChannel) === "feishu") return true;
|
|
455
|
-
if (normalizeMetadataString((isRecord
|
|
456
|
-
if (normalizeMetadataString((isRecord
|
|
457
|
-
if (normalizeMetadataString((isRecord
|
|
458
|
-
const origin = isRecord
|
|
452
|
+
if (normalizeMetadataString((isRecord(value.route) ? value.route : null)?.channel) === "feishu") return true;
|
|
453
|
+
if (normalizeMetadataString((isRecord(value.deliveryContext) ? value.deliveryContext : null)?.channel) === "feishu") return true;
|
|
454
|
+
if (normalizeMetadataString((isRecord(value.pendingFinalDeliveryContext) ? value.pendingFinalDeliveryContext : null)?.channel) === "feishu") return true;
|
|
455
|
+
const origin = isRecord(value.origin) ? value.origin : null;
|
|
459
456
|
const originProvider = normalizeMetadataString(origin?.provider);
|
|
460
457
|
const originSurface = normalizeMetadataString(origin?.surface);
|
|
461
458
|
const originFrom = normalizeMetadataString(origin?.from);
|
|
@@ -547,17 +544,17 @@ function resolveSessionTranscriptCandidates(params) {
|
|
|
547
544
|
return [...candidates].toSorted();
|
|
548
545
|
}
|
|
549
546
|
function isSessionHeader(value) {
|
|
550
|
-
return isRecord
|
|
547
|
+
return isRecord(value) && value.type === "session" && typeof value.id === "string";
|
|
551
548
|
}
|
|
552
549
|
function isBlankUserMessage(value) {
|
|
553
|
-
if (!isRecord
|
|
550
|
+
if (!isRecord(value) || value.type !== "message" || !isRecord(value.message)) return false;
|
|
554
551
|
if (value.message.role !== "user") return false;
|
|
555
552
|
const content = value.message.content;
|
|
556
553
|
if (typeof content === "string") return content.trim().length === 0;
|
|
557
554
|
return Array.isArray(content) && content.length === 0;
|
|
558
555
|
}
|
|
559
556
|
function isUserMessage(value) {
|
|
560
|
-
return isRecord
|
|
557
|
+
return isRecord(value) && value.type === "message" && isRecord(value.message) && value.message.role === "user";
|
|
561
558
|
}
|
|
562
559
|
function inspectSessionTranscript(params) {
|
|
563
560
|
let stat;
|
|
@@ -1431,11 +1428,7 @@ function applyNewAppSecurityPolicy(cfg, accountId, openId, groupPolicy) {
|
|
|
1431
1428
|
next = patchFeishuConfig(next, accountId, groupPatch);
|
|
1432
1429
|
return next;
|
|
1433
1430
|
}
|
|
1434
|
-
|
|
1435
|
-
const loadAppRegistrationModule = async () => {
|
|
1436
|
-
appRegistrationModulePromise ??= import("./app-registration-tgQJUcv3.js");
|
|
1437
|
-
return await appRegistrationModulePromise;
|
|
1438
|
-
};
|
|
1431
|
+
const loadAppRegistrationModule = createLazyRuntimeModule(() => import("./app-registration-DuEyfVY1.js"));
|
|
1439
1432
|
async function promptFeishuDomain(params) {
|
|
1440
1433
|
return await params.prompter.select({
|
|
1441
1434
|
message: t("wizard.feishu.domainPrompt"),
|
|
@@ -1659,7 +1652,7 @@ const feishuSetupWizard = {
|
|
|
1659
1652
|
});
|
|
1660
1653
|
let probeResult = null;
|
|
1661
1654
|
if (configured && account.configured) try {
|
|
1662
|
-
const { probeFeishu } = await import("./probe-
|
|
1655
|
+
const { probeFeishu } = await import("./probe-Cv2M2Ivr.js").then((n) => n.n);
|
|
1663
1656
|
probeResult = await probeFeishu(account);
|
|
1664
1657
|
} catch {}
|
|
1665
1658
|
if (!configured) return [formatFeishuStatusLine("needs-credentials")];
|
|
@@ -1715,13 +1708,13 @@ function readBooleanParam(params, keys) {
|
|
|
1715
1708
|
}
|
|
1716
1709
|
}
|
|
1717
1710
|
function hasLegacyFeishuCardCommandValue(actionValue) {
|
|
1718
|
-
return isRecord$
|
|
1711
|
+
return isRecord$1(actionValue) && actionValue.oc !== "ocf1" && (Boolean(typeof actionValue.command === "string" && actionValue.command.trim()) || Boolean(typeof actionValue.text === "string" && actionValue.text.trim()));
|
|
1719
1712
|
}
|
|
1720
1713
|
function containsLegacyFeishuCardCommandValue(node) {
|
|
1721
1714
|
if (Array.isArray(node)) return node.some((item) => containsLegacyFeishuCardCommandValue(item));
|
|
1722
|
-
if (!isRecord$
|
|
1715
|
+
if (!isRecord$1(node)) return false;
|
|
1723
1716
|
if (node.tag === "button" && hasLegacyFeishuCardCommandValue(node.value)) return true;
|
|
1724
|
-
if (node.tag === "button" && Array.isArray(node.behaviors) && node.behaviors.some((behavior) => isRecord$
|
|
1717
|
+
if (node.tag === "button" && Array.isArray(node.behaviors) && node.behaviors.some((behavior) => isRecord$1(behavior) && hasLegacyFeishuCardCommandValue(behavior.value))) return true;
|
|
1725
1718
|
return Object.values(node).some((value) => containsLegacyFeishuCardCommandValue(value));
|
|
1726
1719
|
}
|
|
1727
1720
|
const meta = {
|
|
@@ -1735,7 +1728,7 @@ const meta = {
|
|
|
1735
1728
|
order: 70,
|
|
1736
1729
|
preferSessionLookupForAnnounceTarget: true
|
|
1737
1730
|
};
|
|
1738
|
-
const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-
|
|
1731
|
+
const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-C6SITclp.js"), "feishuChannelRuntime");
|
|
1739
1732
|
function toFeishuMessageSendResult(result, kind) {
|
|
1740
1733
|
const receipt = result.receipt ?? createFeishuSendReceipt({
|
|
1741
1734
|
messageId: result.messageId,
|
|
@@ -2551,7 +2544,7 @@ const feishuPlugin = createChatChannelPlugin({
|
|
|
2551
2544
|
})
|
|
2552
2545
|
}),
|
|
2553
2546
|
gateway: { startAccount: async (ctx) => {
|
|
2554
|
-
const { monitorFeishuProvider } = await import("./monitor-
|
|
2547
|
+
const { monitorFeishuProvider } = await import("./monitor-Ckch4qvr.js");
|
|
2555
2548
|
const account = resolveFeishuRuntimeAccount({
|
|
2556
2549
|
cfg: ctx.cfg,
|
|
2557
2550
|
accountId: ctx.accountId
|
|
@@ -2562,12 +2555,17 @@ const feishuPlugin = createChatChannelPlugin({
|
|
|
2562
2555
|
port
|
|
2563
2556
|
});
|
|
2564
2557
|
ctx.log?.info(`starting feishu[${ctx.accountId}] (mode: ${account.config?.connectionMode ?? "websocket"})`);
|
|
2558
|
+
const statusSink = createAccountStatusSink({
|
|
2559
|
+
accountId: ctx.accountId,
|
|
2560
|
+
setStatus: ctx.setStatus
|
|
2561
|
+
});
|
|
2565
2562
|
return monitorFeishuProvider({
|
|
2566
2563
|
config: ctx.cfg,
|
|
2567
2564
|
runtime: ctx.runtime,
|
|
2568
2565
|
channelRuntime: ctx.channelRuntime,
|
|
2569
2566
|
abortSignal: ctx.abortSignal,
|
|
2570
|
-
accountId: ctx.accountId
|
|
2567
|
+
accountId: ctx.accountId,
|
|
2568
|
+
statusSink
|
|
2571
2569
|
});
|
|
2572
2570
|
} },
|
|
2573
2571
|
message: feishuMessageAdapter
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as feishuPlugin } from "./channel-
|
|
1
|
+
import { t as feishuPlugin } from "./channel-Bwm5rvHg.js";
|
|
2
2
|
export { feishuPlugin };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, v as parseFeishuCommentTarget } from "./accounts-Cfzht2Hc.js";
|
|
2
|
-
import { h as listFeishuDirectoryPeers, m as listFeishuDirectoryGroups, o as buildFeishuPresentationCardElements } from "./channel-
|
|
2
|
+
import { h as listFeishuDirectoryPeers, m as listFeishuDirectoryGroups, o as buildFeishuPresentationCardElements } from "./channel-Bwm5rvHg.js";
|
|
3
3
|
import { r as createFeishuClient } from "./client-BwgAJuvo.js";
|
|
4
4
|
import { c as getChatInfo, l as getChatMembers, r as cleanupAmbientCommentTypingReaction, t as deliverCommentThreadText, u as getFeishuMemberInfo } from "./drive-djUl8IRC.js";
|
|
5
5
|
import { chunkTextForOutbound } from "./runtime-api.js";
|
|
6
|
-
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-
|
|
7
|
-
import { t as probeFeishu } from "./probe-
|
|
6
|
+
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, y as resolveFeishuIdentityHeaderTitle } from "./send-BJTjDWKi.js";
|
|
7
|
+
import { t as probeFeishu } from "./probe-Cv2M2Ivr.js";
|
|
8
8
|
import { interactiveReplyToPresentation, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
|
|
9
9
|
import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
10
|
import path from "node:path";
|
|
@@ -230,7 +230,7 @@ function buildFeishuPayloadCard(params) {
|
|
|
230
230
|
presentation
|
|
231
231
|
})
|
|
232
232
|
}];
|
|
233
|
-
const identityTitle = params.identity
|
|
233
|
+
const identityTitle = resolveFeishuIdentityHeaderTitle(params.identity);
|
|
234
234
|
const title = presentation?.title ?? identityTitle;
|
|
235
235
|
const template = resolveFeishuCardTemplate(presentation?.tone === "danger" ? "red" : presentation?.tone === "warning" ? "orange" : presentation?.tone === "success" ? "green" : "blue");
|
|
236
236
|
return markRenderedFeishuCard({
|
|
@@ -246,6 +246,9 @@ function buildFeishuPayloadCard(params) {
|
|
|
246
246
|
body: { elements }
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
|
+
function hasVisibleFallbackCommand(blocks) {
|
|
250
|
+
return blocks?.some((block) => block.type === "buttons" && block.buttons.some((button) => !button.disabled && button.action?.type === "command" && !button.url && !button.webApp?.url && !button.web_app?.url)) ?? false;
|
|
251
|
+
}
|
|
249
252
|
function renderFeishuPresentationPayload({ payload, presentation, ctx }) {
|
|
250
253
|
const card = buildFeishuPayloadCard({
|
|
251
254
|
payload,
|
|
@@ -254,6 +257,7 @@ function renderFeishuPresentationPayload({ payload, presentation, ctx }) {
|
|
|
254
257
|
});
|
|
255
258
|
if (!card) return null;
|
|
256
259
|
const existingFeishuData = isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
|
|
260
|
+
const fallbackHasCommand = hasVisibleFallbackCommand(presentation?.blocks);
|
|
257
261
|
return {
|
|
258
262
|
...payload,
|
|
259
263
|
text: renderMessagePresentationFallbackText({
|
|
@@ -264,7 +268,8 @@ function renderFeishuPresentationPayload({ payload, presentation, ctx }) {
|
|
|
264
268
|
...payload.channelData,
|
|
265
269
|
feishu: {
|
|
266
270
|
...existingFeishuData,
|
|
267
|
-
card
|
|
271
|
+
card,
|
|
272
|
+
...fallbackHasCommand ? { fallbackHasCommand: true } : {}
|
|
268
273
|
}
|
|
269
274
|
}
|
|
270
275
|
};
|
|
@@ -385,26 +390,31 @@ const feishuOutbound = {
|
|
|
385
390
|
replyToId: ctx.replyToId,
|
|
386
391
|
threadId: ctx.threadId
|
|
387
392
|
});
|
|
388
|
-
if (parseFeishuCommentTarget(ctx.to))
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
393
|
+
if (parseFeishuCommentTarget(ctx.to)) {
|
|
394
|
+
const normalizedPresentation = normalizeMessagePresentation(ctx.payload.presentation) ?? (() => {
|
|
395
|
+
const interactive = normalizeInteractiveReply(ctx.payload.interactive);
|
|
396
|
+
return interactive ? interactiveReplyToPresentation(interactive) : void 0;
|
|
397
|
+
})();
|
|
398
|
+
const presentationFallbackText = renderMessagePresentationFallbackText({
|
|
399
|
+
text: ctx.payload.text,
|
|
400
|
+
presentation: normalizedPresentation
|
|
401
|
+
});
|
|
402
|
+
const text = hasVisibleFallbackCommand(normalizedPresentation?.blocks) || isRecord(ctx.payload.channelData?.feishu) && ctx.payload.channelData.feishu.fallbackHasCommand === true ? `${presentationFallbackText}\n\n> Interactive buttons are unavailable in Feishu document comments. You can type the command shown above manually.` : presentationFallbackText;
|
|
403
|
+
return await sendTextMediaPayload({
|
|
404
|
+
channel: "feishu",
|
|
405
|
+
ctx: {
|
|
406
|
+
...ctx,
|
|
407
|
+
payload: {
|
|
408
|
+
...ctx.payload,
|
|
409
|
+
text,
|
|
410
|
+
interactive: void 0,
|
|
411
|
+
presentation: void 0,
|
|
412
|
+
channelData: void 0
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
adapter: feishuOutbound
|
|
416
|
+
});
|
|
417
|
+
}
|
|
408
418
|
const mediaUrls = normalizeStringEntries(resolvePayloadMediaUrls(ctx.payload));
|
|
409
419
|
return attachChannelToResult("feishu", await sendPayloadMediaSequenceAndFinalize({
|
|
410
420
|
text: ctx.payload.text ?? "",
|
|
@@ -463,7 +473,7 @@ const feishuOutbound = {
|
|
|
463
473
|
}).config?.renderMode ?? "auto";
|
|
464
474
|
if (renderMode === "card" || renderMode === "auto" && shouldUseCard(text)) {
|
|
465
475
|
const header = identity ? {
|
|
466
|
-
title: identity
|
|
476
|
+
title: resolveFeishuIdentityHeaderTitle(identity),
|
|
467
477
|
template: "blue"
|
|
468
478
|
} : void 0;
|
|
469
479
|
return await sendStructuredCardFeishu({
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-Cfzht2Hc.js";
|
|
2
|
-
import { f as fetchBotIdentityForMonitor } from "./monitor.state-
|
|
2
|
+
import { f as fetchBotIdentityForMonitor } from "./monitor.state-R4ZgNpac.js";
|
|
3
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
3
4
|
//#region extensions/feishu/src/monitor.ts
|
|
4
|
-
|
|
5
|
-
async function loadMonitorAccountRuntime() {
|
|
6
|
-
monitorAccountRuntimePromise ??= import("./monitor.account-C3SH96dD.js");
|
|
7
|
-
return await monitorAccountRuntimePromise;
|
|
8
|
-
}
|
|
5
|
+
const loadMonitorAccountRuntime = createLazyRuntimeModule(() => import("./monitor.account-GXGIJrgw.js"));
|
|
9
6
|
async function monitorFeishuProvider(opts = {}) {
|
|
10
7
|
const cfg = opts.config;
|
|
11
8
|
if (!cfg) throw new Error("Config is required for Feishu monitor");
|
|
@@ -22,7 +19,8 @@ async function monitorFeishuProvider(opts = {}) {
|
|
|
22
19
|
account,
|
|
23
20
|
channelRuntime: opts.channelRuntime,
|
|
24
21
|
runtime: opts.runtime,
|
|
25
|
-
abortSignal: opts.abortSignal
|
|
22
|
+
abortSignal: opts.abortSignal,
|
|
23
|
+
...opts.statusSink ? { statusSink: opts.statusSink } : {}
|
|
26
24
|
});
|
|
27
25
|
}
|
|
28
26
|
const accounts = listEnabledFeishuAccounts(cfg);
|
|
@@ -53,7 +51,8 @@ async function monitorFeishuProvider(opts = {}) {
|
|
|
53
51
|
kind: "prefetched",
|
|
54
52
|
botOpenId,
|
|
55
53
|
botName
|
|
56
|
-
}
|
|
54
|
+
},
|
|
55
|
+
...opts.statusSink ? { statusSink: opts.statusSink } : {}
|
|
57
56
|
}));
|
|
58
57
|
}
|
|
59
58
|
await Promise.all(monitorPromises);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { _ as normalizeCommentFileType, c as encodeQuery, d as isRecord$1, f as normalizeString, g as buildFeishuCommentTarget, h as requestFeishuApi, l as extractReplyText, m as readString, o as resolveFeishuAccount, p as parseCommentContentElements, s as resolveFeishuRuntimeAccount } from "./accounts-Cfzht2Hc.js";
|
|
2
2
|
import { i as resolveReceiveIdType } from "./targets-BUjQ1TcA.js";
|
|
3
|
-
import { c as normalizeFeishuAllowEntry, d as resolveFeishuGroupConversationIngressAccess, f as resolveFeishuGroupSenderActivationIngressAccess, l as resolveFeishuDmIngressAccess, p as resolveFeishuReplyPolicy, s as hasExplicitFeishuGroupConfig, u as resolveFeishuGroupConfig } from "./channel-
|
|
3
|
+
import { c as normalizeFeishuAllowEntry, d as resolveFeishuGroupConversationIngressAccess, f as resolveFeishuGroupSenderActivationIngressAccess, l as resolveFeishuDmIngressAccess, p as resolveFeishuReplyPolicy, s as hasExplicitFeishuGroupConfig, u as resolveFeishuGroupConfig } from "./channel-Bwm5rvHg.js";
|
|
4
4
|
import { c as decodeFeishuCardAction, o as buildFeishuCardActionTextFallback, s as createFeishuCardInteractionEnvelope } from "./send-result-DSsIa4-p.js";
|
|
5
5
|
import { t as buildFeishuConversationId } from "./conversation-id-DuL575sn.js";
|
|
6
6
|
import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
|
|
7
7
|
import { a as getFeishuUserAgent, i as createFeishuWSClient, n as createEventDispatcher, r as createFeishuClient } from "./client-BwgAJuvo.js";
|
|
8
8
|
import { c as getChatInfo, i as createCommentTypingReactionLifecycle, t as deliverCommentThreadText } from "./drive-djUl8IRC.js";
|
|
9
9
|
import { t as createFeishuThreadBindingManager } from "./thread-bindings-V0bwk0A1.js";
|
|
10
|
-
import { createReplyPrefixContext, evaluateSupplementalContextVisibility,
|
|
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 saveMessageResourceFeishu, n as getMessageFeishu, p as isFeishuGroupChatType, r as listFeishuThreadMessages, s as sendMessageFeishu, u as extractMentionTargets } from "./send-
|
|
12
|
-
import { i as waitForAbortableDelay, r as raceWithTimeoutAndAbort } from "./probe-
|
|
13
|
-
import { a as clearFeishuBotIdentityState, c as httpServers, d as wsClients, f as fetchBotIdentityForMonitor, i as botOpenIds, l as recordWebhookStatus, n as FEISHU_WEBHOOK_MAX_BODY_BYTES, o as closeTrackedFeishuHttpServer, r as botNames, s as feishuWebhookRateLimiter, t as FEISHU_WEBHOOK_BODY_TIMEOUT_MS, u as setFeishuBotIdentityState } from "./monitor.state-
|
|
10
|
+
import { createReplyPrefixContext, evaluateSupplementalContextVisibility, getSessionEntry, normalizeAgentId as normalizeAgentId$2, resolveChannelContextVisibilityMode } 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 saveMessageResourceFeishu, n as getMessageFeishu, p as isFeishuGroupChatType, r as listFeishuThreadMessages, s as sendMessageFeishu, u as extractMentionTargets, v as resolveFeishuIdentityEmoji } from "./send-BJTjDWKi.js";
|
|
12
|
+
import { i as waitForAbortableDelay, r as raceWithTimeoutAndAbort } from "./probe-Cv2M2Ivr.js";
|
|
13
|
+
import { a as clearFeishuBotIdentityState, c as httpServers, d as wsClients, f as fetchBotIdentityForMonitor, i as botOpenIds, l as recordWebhookStatus, n as FEISHU_WEBHOOK_MAX_BODY_BYTES, o as closeTrackedFeishuHttpServer, r as botNames, s as feishuWebhookRateLimiter, t as FEISHU_WEBHOOK_BODY_TIMEOUT_MS, u as setFeishuBotIdentityState } from "./monitor.state-R4ZgNpac.js";
|
|
14
14
|
import { createChannelMessageReplyPipeline, formatChannelProgressDraftLineForEntry, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
15
|
import { createChannelPairingController, createChannelPairingController as createChannelPairingController$1 } from "openclaw/plugin-sdk/channel-pairing";
|
|
16
16
|
import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
|
|
@@ -32,6 +32,7 @@ import { resolvePinnedMainDmOwnerFromAllowlist, safeEqualSecret } from "openclaw
|
|
|
32
32
|
import { buildChannelInboundEventContext, toInboundMediaFacts } from "openclaw/plugin-sdk/channel-inbound";
|
|
33
33
|
import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
34
34
|
import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
35
|
+
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
35
36
|
import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
|
|
36
37
|
import { formatReasoningMessage } from "openclaw/plugin-sdk/agent-runtime";
|
|
37
38
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
@@ -844,10 +845,11 @@ function resolveFeishuReasoningPreviewEnabled(params) {
|
|
|
844
845
|
const configDefault = resolveFeishuConfigReasoningDefault(params.cfg, params.agentId);
|
|
845
846
|
if (!params.sessionKey) return configDefault === "stream";
|
|
846
847
|
try {
|
|
847
|
-
const level =
|
|
848
|
-
|
|
849
|
-
sessionKey: params.sessionKey
|
|
850
|
-
|
|
848
|
+
const level = getSessionEntry({
|
|
849
|
+
storePath: params.storePath,
|
|
850
|
+
sessionKey: params.sessionKey,
|
|
851
|
+
readConsistency: "latest"
|
|
852
|
+
})?.reasoningLevel;
|
|
851
853
|
if (level === "on" || level === "stream" || level === "off") return level === "stream";
|
|
852
854
|
} catch {
|
|
853
855
|
return false;
|
|
@@ -919,7 +921,7 @@ async function getToken(creds) {
|
|
|
919
921
|
function truncateSummary(text, max = 50) {
|
|
920
922
|
if (!text) return "";
|
|
921
923
|
const clean = text.replace(/\n/g, " ").trim();
|
|
922
|
-
return clean.length <= max ? clean : clean
|
|
924
|
+
return clean.length <= max ? clean : sliceUtf16Safe(clean, 0, max - 3) + "...";
|
|
923
925
|
}
|
|
924
926
|
function hasNaturalStreamingBoundary(text) {
|
|
925
927
|
return /[\n。!?!?;;::]$/.test(text);
|
|
@@ -1148,7 +1150,7 @@ var FeishuStreamingSession = class {
|
|
|
1148
1150
|
this.flushTimer = null;
|
|
1149
1151
|
const pending = this.pendingText;
|
|
1150
1152
|
if (!pending || this.closed) return;
|
|
1151
|
-
this.update(pending);
|
|
1153
|
+
this.update(pending).catch((error) => this.log?.(`Scheduled flush update failed: ${String(error)}`));
|
|
1152
1154
|
}, delayMs);
|
|
1153
1155
|
}
|
|
1154
1156
|
async update(text) {
|
|
@@ -1455,7 +1457,7 @@ function normalizeEpochMs(timestamp) {
|
|
|
1455
1457
|
/** Build a card header from agent identity config. */
|
|
1456
1458
|
function resolveCardHeader(agentId, identity) {
|
|
1457
1459
|
const name = identity?.name?.trim() || (agentId === "main" ? "" : agentId);
|
|
1458
|
-
const emoji = identity?.emoji
|
|
1460
|
+
const emoji = resolveFeishuIdentityEmoji(identity?.emoji);
|
|
1459
1461
|
const title = (emoji ? `${emoji} ${name}` : name).trim();
|
|
1460
1462
|
if (!title) return;
|
|
1461
1463
|
return {
|
|
@@ -1472,7 +1474,7 @@ function resolveCardNote(agentId, identity, prefixCtx) {
|
|
|
1472
1474
|
}
|
|
1473
1475
|
function createFeishuReplyDispatcher(params) {
|
|
1474
1476
|
const core = getFeishuRuntime();
|
|
1475
|
-
const { cfg, agentId, chatId, replyToMessageId, typingTargetMessageId: explicitTypingTargetMessageId, skipReplyToInMessages, replyInThread, threadReply, rootId, accountId, identity, mentionTargets } = params;
|
|
1477
|
+
const { cfg, agentId, chatId, sendTarget, replyToMessageId, typingTargetMessageId: explicitTypingTargetMessageId, skipReplyToInMessages, replyInThread, threadReply, rootId, accountId, identity, mentionTargets } = params;
|
|
1476
1478
|
const sendReplyToMessageId = skipReplyToInMessages ? void 0 : replyToMessageId;
|
|
1477
1479
|
const typingTargetMessageId = explicitTypingTargetMessageId?.trim() || replyToMessageId;
|
|
1478
1480
|
const threadReplyMode = threadReply === true;
|
|
@@ -1549,6 +1551,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1549
1551
|
let lastSnapshotTextLength = 0;
|
|
1550
1552
|
let hasStreamingFinalText = false;
|
|
1551
1553
|
const deliveredFinalTexts = /* @__PURE__ */ new Set();
|
|
1554
|
+
let sentIndependentBlockText = false;
|
|
1552
1555
|
let partialUpdateQueue = Promise.resolve();
|
|
1553
1556
|
let streamingStartPromise = null;
|
|
1554
1557
|
let streamingClosedForReply = false;
|
|
@@ -1611,8 +1614,9 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1611
1614
|
try {
|
|
1612
1615
|
const cardHeader = resolveCardHeader(agentId, identity);
|
|
1613
1616
|
const cardNote = resolveCardNote(agentId, identity, prefixContext.prefixContext);
|
|
1614
|
-
|
|
1615
|
-
|
|
1617
|
+
const streamingTarget = sendTarget.replace(/^(feishu|lark):/i, "").replace(/^(chat|user|group|dm|open_id):/i, "").trim();
|
|
1618
|
+
await streaming.start(streamingTarget, resolveReceiveIdType(sendTarget), {
|
|
1619
|
+
replyToMessageId: sendReplyToMessageId,
|
|
1616
1620
|
replyInThread: effectiveReplyInThread,
|
|
1617
1621
|
rootId,
|
|
1618
1622
|
header: cardHeader,
|
|
@@ -1694,7 +1698,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1694
1698
|
send: async ({ mediaUrl }) => {
|
|
1695
1699
|
const result = await sendMediaFeishu({
|
|
1696
1700
|
cfg,
|
|
1697
|
-
to:
|
|
1701
|
+
to: sendTarget,
|
|
1698
1702
|
mediaUrl,
|
|
1699
1703
|
replyToMessageId: sendReplyToMessageId,
|
|
1700
1704
|
replyInThread: effectiveReplyInThread,
|
|
@@ -1711,7 +1715,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1711
1715
|
sendChunk: async ({ chunk }) => {
|
|
1712
1716
|
await sendMessageFeishu({
|
|
1713
1717
|
cfg,
|
|
1714
|
-
to:
|
|
1718
|
+
to: sendTarget,
|
|
1715
1719
|
text: chunk,
|
|
1716
1720
|
replyToMessageId: sendReplyToMessageId,
|
|
1717
1721
|
replyInThread: effectiveReplyInThread,
|
|
@@ -1732,7 +1736,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1732
1736
|
sendChunk: async ({ chunk }) => {
|
|
1733
1737
|
await sendMessageFeishu({
|
|
1734
1738
|
cfg,
|
|
1735
|
-
to:
|
|
1739
|
+
to: sendTarget,
|
|
1736
1740
|
text: chunk,
|
|
1737
1741
|
replyToMessageId: sendReplyToMessageId,
|
|
1738
1742
|
replyInThread: effectiveReplyInThread,
|
|
@@ -1753,7 +1757,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1753
1757
|
}
|
|
1754
1758
|
await sendMessageFeishu({
|
|
1755
1759
|
cfg,
|
|
1756
|
-
to:
|
|
1760
|
+
to: sendTarget,
|
|
1757
1761
|
text: NO_VISIBLE_REPLY_FALLBACK_TEXT,
|
|
1758
1762
|
replyToMessageId: sendReplyToMessageId,
|
|
1759
1763
|
replyInThread: effectiveReplyInThread,
|
|
@@ -1789,6 +1793,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1789
1793
|
if (!replyLifecycleStateInitialized) {
|
|
1790
1794
|
replyLifecycleStateInitialized = true;
|
|
1791
1795
|
deliveredFinalTexts.clear();
|
|
1796
|
+
sentIndependentBlockText = false;
|
|
1792
1797
|
streamingClosedForReply = false;
|
|
1793
1798
|
streamingCloseErroredForReply = false;
|
|
1794
1799
|
visibleReplySent = false;
|
|
@@ -1824,7 +1829,31 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1824
1829
|
if (shouldDiscardStreamingPreview) await discardStreamingPreview();
|
|
1825
1830
|
if (shouldDeliverText) {
|
|
1826
1831
|
if (info?.kind === "block") {
|
|
1827
|
-
if (!useStreamingCard)
|
|
1832
|
+
if (!useStreamingCard) {
|
|
1833
|
+
if (coreBlockStreamingEnabled) {
|
|
1834
|
+
const isFirstBlock = !sentIndependentBlockText;
|
|
1835
|
+
await sendChunkedTextReply({
|
|
1836
|
+
text,
|
|
1837
|
+
useCard: false,
|
|
1838
|
+
infoKind: "block",
|
|
1839
|
+
sendChunk: async ({ chunk, isFirst }) => {
|
|
1840
|
+
await sendMessageFeishu({
|
|
1841
|
+
cfg,
|
|
1842
|
+
to: sendTarget,
|
|
1843
|
+
text: chunk,
|
|
1844
|
+
replyToMessageId: sendReplyToMessageId,
|
|
1845
|
+
replyInThread: effectiveReplyInThread,
|
|
1846
|
+
allowTopLevelReplyFallback,
|
|
1847
|
+
accountId,
|
|
1848
|
+
...isFirstBlock && isFirst && mentionTargets?.length ? { mentions: mentionTargets } : {}
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1852
|
+
sentIndependentBlockText = true;
|
|
1853
|
+
if (hasMedia) await sendMediaReplies(payload);
|
|
1854
|
+
}
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1828
1857
|
startStreaming();
|
|
1829
1858
|
if (streamingStartPromise) await streamingStartPromise;
|
|
1830
1859
|
}
|
|
@@ -1858,7 +1887,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1858
1887
|
sendChunk: async ({ chunk }) => {
|
|
1859
1888
|
await sendStructuredCardFeishu({
|
|
1860
1889
|
cfg,
|
|
1861
|
-
to:
|
|
1890
|
+
to: sendTarget,
|
|
1862
1891
|
text: chunk,
|
|
1863
1892
|
replyToMessageId: sendReplyToMessageId,
|
|
1864
1893
|
replyInThread: effectiveReplyInThread,
|
|
@@ -1876,7 +1905,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1876
1905
|
sendChunk: async ({ chunk, isFirst }) => {
|
|
1877
1906
|
await sendMessageFeishu({
|
|
1878
1907
|
cfg,
|
|
1879
|
-
to:
|
|
1908
|
+
to: sendTarget,
|
|
1880
1909
|
text: chunk,
|
|
1881
1910
|
replyToMessageId: sendReplyToMessageId,
|
|
1882
1911
|
replyInThread: effectiveReplyInThread,
|
|
@@ -2098,7 +2127,7 @@ function formatMentionNameForAgentContext(name) {
|
|
|
2098
2127
|
const normalized = Array.from(name, (char) => {
|
|
2099
2128
|
return char.charCodeAt(0) < 32 || char === "[" || char === "]" ? " " : char;
|
|
2100
2129
|
}).join("").replace(/\s+/g, " ").trim();
|
|
2101
|
-
const bounded = normalized.length > MAX_MENTION_CONTEXT_NAME_LENGTH ? `${normalized
|
|
2130
|
+
const bounded = normalized.length > MAX_MENTION_CONTEXT_NAME_LENGTH ? `${truncateUtf16Safe(normalized, MAX_MENTION_CONTEXT_NAME_LENGTH - 3)}...` : normalized;
|
|
2102
2131
|
return JSON.stringify(bounded || "unknown");
|
|
2103
2132
|
}
|
|
2104
2133
|
function buildFeishuAgentBody(params) {
|
|
@@ -2538,7 +2567,7 @@ async function handleFeishuMessage(params) {
|
|
|
2538
2567
|
return;
|
|
2539
2568
|
}
|
|
2540
2569
|
}
|
|
2541
|
-
const preview = ctx.content.replace(/\s+/g, " ")
|
|
2570
|
+
const preview = truncateUtf16Safe(ctx.content.replace(/\s+/g, " "), 160);
|
|
2542
2571
|
const inboundLabel = isGroup ? `Feishu[${account.accountId}] message in group ${ctx.chatId}` : `Feishu[${account.accountId}] DM from ${ctx.senderOpenId}`;
|
|
2543
2572
|
const contextVisibilityMode = resolveChannelContextVisibilityMode({
|
|
2544
2573
|
cfg: effectiveCfg,
|
|
@@ -2576,7 +2605,7 @@ async function handleFeishuMessage(params) {
|
|
|
2576
2605
|
senderType: quotedMessageInfo.senderType
|
|
2577
2606
|
})) {
|
|
2578
2607
|
quotedContent = quotedMessageInfo.content;
|
|
2579
|
-
log(`feishu[${account.accountId}]: fetched quoted message: ${quotedContent
|
|
2608
|
+
log(`feishu[${account.accountId}]: fetched quoted message: ${truncateUtf16Safe(quotedContent, 100)}`);
|
|
2580
2609
|
} else if (quotedMessageInfo) log(`feishu[${account.accountId}]: skipped quoted message from sender ${quotedMessageInfo.senderId ?? "unknown"} (mode=${contextVisibilityMode})`);
|
|
2581
2610
|
} catch (err) {
|
|
2582
2611
|
log(`feishu[${account.accountId}]: failed to fetch quoted message: ${String(err)}`);
|
|
@@ -2822,7 +2851,8 @@ async function handleFeishuMessage(params) {
|
|
|
2822
2851
|
access: {
|
|
2823
2852
|
mentions: {
|
|
2824
2853
|
canDetectMention: isGroup,
|
|
2825
|
-
wasMentioned
|
|
2854
|
+
wasMentioned,
|
|
2855
|
+
requireMention
|
|
2826
2856
|
},
|
|
2827
2857
|
commands: { authorized: commandAuthorized }
|
|
2828
2858
|
},
|
|
@@ -2906,6 +2936,7 @@ async function handleFeishuMessage(params) {
|
|
|
2906
2936
|
agentId,
|
|
2907
2937
|
runtime,
|
|
2908
2938
|
chatId: ctx.chatId,
|
|
2939
|
+
sendTarget: feishuTo,
|
|
2909
2940
|
allowReasoningPreview,
|
|
2910
2941
|
replyToMessageId: replyTargetMessageId,
|
|
2911
2942
|
typingTargetMessageId,
|
|
@@ -3049,6 +3080,7 @@ async function handleFeishuMessage(params) {
|
|
|
3049
3080
|
agentId: route.agentId,
|
|
3050
3081
|
runtime,
|
|
3051
3082
|
chatId: ctx.chatId,
|
|
3083
|
+
sendTarget: feishuTo,
|
|
3052
3084
|
allowReasoningPreview,
|
|
3053
3085
|
replyToMessageId: replyTargetMessageId,
|
|
3054
3086
|
typingTargetMessageId,
|
|
@@ -3901,7 +3933,7 @@ function safeJsonStringify(value) {
|
|
|
3901
3933
|
function truncatePromptText(text, maxLength = FEISHU_PROMPT_TEXT_LIMIT) {
|
|
3902
3934
|
const normalized = normalizeString(text);
|
|
3903
3935
|
if (!normalized) return "";
|
|
3904
|
-
return normalized.length > maxLength ? `${normalized
|
|
3936
|
+
return normalized.length > maxLength ? `${sliceUtf16Safe(normalized, 0, maxLength - 1)}…` : normalized;
|
|
3905
3937
|
}
|
|
3906
3938
|
function formatPromptTextValue(text) {
|
|
3907
3939
|
return safeJsonStringify(truncatePromptText(text) || "");
|
|
@@ -4474,7 +4506,7 @@ async function resolveDriveCommentEventTurn(params) {
|
|
|
4474
4506
|
nearestBotWholeCommentAfter: resolved.context.nearestBotWholeCommentAfter,
|
|
4475
4507
|
nearestBotWholeCommentBefore: resolved.context.nearestBotWholeCommentBefore
|
|
4476
4508
|
});
|
|
4477
|
-
const preview = prompt.replace(/\s+/g, " ")
|
|
4509
|
+
const preview = truncateUtf16Safe(prompt.replace(/\s+/g, " "), 160);
|
|
4478
4510
|
return {
|
|
4479
4511
|
eventId: resolved.eventId,
|
|
4480
4512
|
messageId: `drive-comment:${resolved.eventId}`,
|
|
@@ -4933,7 +4965,7 @@ function resolveFeishuDebounceMentions(params) {
|
|
|
4933
4965
|
const botMentions = merged.filter((mention) => mention.id.open_id?.trim() === normalizedBotOpenId);
|
|
4934
4966
|
return botMentions.length > 0 ? botMentions : void 0;
|
|
4935
4967
|
}
|
|
4936
|
-
function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, runtime, chatHistories, fireAndForget, handleMessage, resolveDebounceText: resolveText, hasProcessedMessage, recordProcessedMessage, getBotOpenId = () => void 0, getBotName = () => void 0, resolveSequentialKey = ({ accountId: accountIdLocal, event }) => `feishu:${accountIdLocal}:${event.message.chat_id?.trim() || "unknown"}
|
|
4968
|
+
function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, runtime, chatHistories, fireAndForget, handleMessage, resolveDebounceText: resolveText, hasProcessedMessage, recordProcessedMessage, getBotOpenId = () => void 0, getBotName = () => void 0, resolveSequentialKey = ({ accountId: accountIdLocal, event }) => `feishu:${accountIdLocal}:${event.message.chat_id?.trim() || "unknown"}`, statusSink }) {
|
|
4937
4969
|
const inboundDebounceMs = channelRuntime.debounce.resolveInboundDebounceMs({
|
|
4938
4970
|
cfg,
|
|
4939
4971
|
channel: "feishu"
|
|
@@ -5034,6 +5066,7 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5034
5066
|
}
|
|
5035
5067
|
});
|
|
5036
5068
|
return async (data) => {
|
|
5069
|
+
statusSink?.({ lastEventAt: Date.now() });
|
|
5037
5070
|
const event = parseFeishuMessageEventPayload(data);
|
|
5038
5071
|
if (!event) {
|
|
5039
5072
|
error(`feishu[${accountId}]: ignoring malformed message event payload`);
|
|
@@ -5161,7 +5194,7 @@ function waitForFeishuWsCycleEnd(params) {
|
|
|
5161
5194
|
params.terminalError.then(finish);
|
|
5162
5195
|
});
|
|
5163
5196
|
}
|
|
5164
|
-
async function monitorWebSocket({ account, accountId, runtime, abortSignal, eventDispatcher }) {
|
|
5197
|
+
async function monitorWebSocket({ account, accountId, runtime, abortSignal, eventDispatcher, statusSink }) {
|
|
5165
5198
|
const log = runtime?.log ?? console.log;
|
|
5166
5199
|
const error = runtime?.error ?? console.error;
|
|
5167
5200
|
let attempt = 0;
|
|
@@ -5180,8 +5213,28 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
5180
5213
|
}
|
|
5181
5214
|
error(`feishu[${accountId}]: WebSocket SDK reported recoverable error: ${formatFeishuWsErrorForLog(err)}`);
|
|
5182
5215
|
};
|
|
5216
|
+
const publishWsConnected = () => {
|
|
5217
|
+
const connectedAt = Date.now();
|
|
5218
|
+
statusSink?.({
|
|
5219
|
+
connected: true,
|
|
5220
|
+
lastConnectedAt: connectedAt,
|
|
5221
|
+
lastEventAt: connectedAt,
|
|
5222
|
+
lastError: null
|
|
5223
|
+
});
|
|
5224
|
+
};
|
|
5225
|
+
const publishWsReconnecting = () => {
|
|
5226
|
+
statusSink?.({
|
|
5227
|
+
connected: false,
|
|
5228
|
+
lastEventAt: Date.now()
|
|
5229
|
+
});
|
|
5230
|
+
};
|
|
5183
5231
|
log(`feishu[${accountId}]: starting WebSocket connection...`);
|
|
5184
|
-
wsClient = await createFeishuWSClient(account, {
|
|
5232
|
+
wsClient = await createFeishuWSClient(account, {
|
|
5233
|
+
onError: handleWsError,
|
|
5234
|
+
onReady: publishWsConnected,
|
|
5235
|
+
onReconnected: publishWsConnected,
|
|
5236
|
+
onReconnecting: publishWsReconnecting
|
|
5237
|
+
});
|
|
5185
5238
|
if (abortSignal?.aborted) {
|
|
5186
5239
|
cleanupFeishuWsClient({
|
|
5187
5240
|
accountId,
|
|
@@ -5216,6 +5269,10 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
5216
5269
|
clearIdentity: false
|
|
5217
5270
|
});
|
|
5218
5271
|
if (abortSignal?.aborted) break;
|
|
5272
|
+
statusSink?.({
|
|
5273
|
+
connected: false,
|
|
5274
|
+
lastEventAt: Date.now()
|
|
5275
|
+
});
|
|
5219
5276
|
attempt += 1;
|
|
5220
5277
|
const delayMs = getFeishuWsReconnectDelayMs(attempt);
|
|
5221
5278
|
error(`feishu[${accountId}]: WebSocket connection ended, recreating client in ${delayMs}ms: ${formatFeishuWsErrorForLog(cycleEnd)}`);
|
|
@@ -5228,6 +5285,10 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
5228
5285
|
clearIdentity: false
|
|
5229
5286
|
});
|
|
5230
5287
|
if (abortSignal?.aborted) break;
|
|
5288
|
+
statusSink?.({
|
|
5289
|
+
connected: false,
|
|
5290
|
+
lastEventAt: Date.now()
|
|
5291
|
+
});
|
|
5231
5292
|
attempt += 1;
|
|
5232
5293
|
const delayMs = getFeishuWsReconnectDelayMs(attempt);
|
|
5233
5294
|
error(`feishu[${accountId}]: WebSocket start failed, retrying in ${delayMs}ms: ${formatFeishuWsErrorForLog(err)}`);
|
|
@@ -5241,7 +5302,7 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
5241
5302
|
clearIdentity: true
|
|
5242
5303
|
});
|
|
5243
5304
|
}
|
|
5244
|
-
async function monitorWebhook({ account, accountId, runtime, abortSignal, eventDispatcher }) {
|
|
5305
|
+
async function monitorWebhook({ account, accountId, runtime, abortSignal, eventDispatcher, statusSink }) {
|
|
5245
5306
|
const log = runtime?.log ?? console.log;
|
|
5246
5307
|
const error = runtime?.error ?? console.error;
|
|
5247
5308
|
const encryptKey = account.encryptKey?.trim();
|
|
@@ -5254,6 +5315,13 @@ async function monitorWebhook({ account, accountId, runtime, abortSignal, eventD
|
|
|
5254
5315
|
server.on("request", (req, res) => {
|
|
5255
5316
|
res.on("finish", () => {
|
|
5256
5317
|
recordWebhookStatus(runtime, accountId, path, res.statusCode);
|
|
5318
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
5319
|
+
const inboundAt = Date.now();
|
|
5320
|
+
statusSink?.({
|
|
5321
|
+
lastEventAt: inboundAt,
|
|
5322
|
+
lastTransportActivityAt: inboundAt
|
|
5323
|
+
});
|
|
5324
|
+
}
|
|
5257
5325
|
});
|
|
5258
5326
|
if (!applyBasicWebhookRequestGuards({
|
|
5259
5327
|
req,
|
|
@@ -5338,6 +5406,13 @@ async function monitorWebhook({ account, accountId, runtime, abortSignal, eventD
|
|
|
5338
5406
|
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
5339
5407
|
server.listen(port, host, () => {
|
|
5340
5408
|
log(`feishu[${accountId}]: Webhook server listening on ${host}:${port}`);
|
|
5409
|
+
const webhookConnectedAt = Date.now();
|
|
5410
|
+
statusSink?.({
|
|
5411
|
+
connected: true,
|
|
5412
|
+
lastConnectedAt: webhookConnectedAt,
|
|
5413
|
+
lastEventAt: webhookConnectedAt,
|
|
5414
|
+
lastError: null
|
|
5415
|
+
});
|
|
5341
5416
|
});
|
|
5342
5417
|
server.on("error", (err) => {
|
|
5343
5418
|
error(`feishu[${accountId}]: Webhook server error: ${err}`);
|
|
@@ -5505,7 +5580,8 @@ function registerEventHandlers(eventDispatcher, context) {
|
|
|
5505
5580
|
recordProcessedMessage: recordProcessedFeishuMessage,
|
|
5506
5581
|
getBotOpenId: (id) => botOpenIds.get(id),
|
|
5507
5582
|
getBotName: (id) => botNames.get(id),
|
|
5508
|
-
resolveSequentialKey: getFeishuSequentialKey
|
|
5583
|
+
resolveSequentialKey: getFeishuSequentialKey,
|
|
5584
|
+
...context.statusSink ? { statusSink: context.statusSink } : {}
|
|
5509
5585
|
}),
|
|
5510
5586
|
"im.message.message_read_v1": async () => {},
|
|
5511
5587
|
"im.chat.access_event.bot_p2p_chat_entered_v1": async () => {},
|
|
@@ -5656,24 +5732,27 @@ async function monitorSingleAccount(params) {
|
|
|
5656
5732
|
registerEventHandlers(eventDispatcher, {
|
|
5657
5733
|
cfg,
|
|
5658
5734
|
accountId,
|
|
5659
|
-
channelRuntime: params.channelRuntime
|
|
5735
|
+
channelRuntime: params.channelRuntime?.inbound ? params.channelRuntime : getFeishuRuntime().channel,
|
|
5660
5736
|
runtime,
|
|
5661
5737
|
chatHistories,
|
|
5662
|
-
fireAndForget: params.fireAndForget ?? true
|
|
5738
|
+
fireAndForget: params.fireAndForget ?? true,
|
|
5739
|
+
...params.statusSink ? { statusSink: params.statusSink } : {}
|
|
5663
5740
|
});
|
|
5664
5741
|
if (connectionMode === "webhook") return await monitorWebhook({
|
|
5665
5742
|
account,
|
|
5666
5743
|
accountId,
|
|
5667
5744
|
runtime,
|
|
5668
5745
|
abortSignal,
|
|
5669
|
-
eventDispatcher
|
|
5746
|
+
eventDispatcher,
|
|
5747
|
+
...params.statusSink ? { statusSink: params.statusSink } : {}
|
|
5670
5748
|
});
|
|
5671
5749
|
return await monitorWebSocket({
|
|
5672
5750
|
account,
|
|
5673
5751
|
accountId,
|
|
5674
5752
|
runtime,
|
|
5675
5753
|
abortSignal,
|
|
5676
|
-
eventDispatcher
|
|
5754
|
+
eventDispatcher,
|
|
5755
|
+
...params.statusSink ? { statusSink: params.statusSink } : {}
|
|
5677
5756
|
});
|
|
5678
5757
|
} finally {
|
|
5679
5758
|
threadBindingManager?.stop();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as probeFeishu } from "./probe-
|
|
1
|
+
import { t as probeFeishu } from "./probe-Cv2M2Ivr.js";
|
|
2
2
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, createWebhookAnomalyTracker } from "openclaw/plugin-sdk/webhook-ingress";
|
|
@@ -41,6 +41,7 @@ function waitForAbortableDelay(delayMs, abortSignal) {
|
|
|
41
41
|
if (abortSignal?.aborted) return Promise.resolve(false);
|
|
42
42
|
return new Promise((resolve) => {
|
|
43
43
|
let settled = false;
|
|
44
|
+
let timer = void 0;
|
|
44
45
|
const finish = (value) => {
|
|
45
46
|
if (settled) return;
|
|
46
47
|
settled = true;
|
|
@@ -56,7 +57,7 @@ function waitForAbortableDelay(delayMs, abortSignal) {
|
|
|
56
57
|
finish(false);
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
+
timer = setTimeout(() => finish(true), resolveTimerTimeoutMs(delayMs, 1));
|
|
60
61
|
timer.unref?.();
|
|
61
62
|
});
|
|
62
63
|
}
|
package/dist/runtime-api.js
CHANGED
|
@@ -4,10 +4,10 @@ import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pair
|
|
|
4
4
|
import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
|
|
5
5
|
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
6
6
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
7
|
-
import {
|
|
7
|
+
import { getSessionEntry } from "openclaw/plugin-sdk/session-store-runtime";
|
|
8
8
|
import { DEFAULT_ACCOUNT_ID, buildChannelConfigSchema, createActionGate, createDedupeCache } from "openclaw/plugin-sdk/core";
|
|
9
9
|
import { buildAgentMediaPayload } from "openclaw/plugin-sdk/agent-media-payload";
|
|
10
10
|
import { evaluateSupplementalContextVisibility, filterSupplementalContextItems, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
11
11
|
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
12
12
|
import { isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
|
|
13
|
-
export { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE, buildAgentMediaPayload, buildChannelConfigSchema, buildProbeChannelStatusSummary, chunkTextForOutbound, createActionGate, createChannelPairingController, createDedupeCache, createDefaultChannelRuntimeState, createReplyPrefixContext, evaluateSupplementalContextVisibility, filterSupplementalContextItems,
|
|
13
|
+
export { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE, buildAgentMediaPayload, buildChannelConfigSchema, buildProbeChannelStatusSummary, chunkTextForOutbound, createActionGate, createChannelPairingController, createDedupeCache, createDefaultChannelRuntimeState, createReplyPrefixContext, evaluateSupplementalContextVisibility, filterSupplementalContextItems, getSessionEntry, isRequestBodyLimitError, normalizeAgentId, readJsonFileWithFallback, readRequestBodyWithLimit, requestBodyErrorToText, resolveChannelContextVisibilityMode, setFeishuRuntime };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectConditionalChannelFieldAssignments,
|
|
1
|
+
import { collectConditionalChannelFieldAssignments, collectSecretInputAssignment, getChannelSurface, hasConfiguredSecretInputValue, hasOwnProperty, isBaseFieldActiveForChannelSurface, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
2
|
//#region extensions/feishu/src/secret-contract.ts
|
|
3
3
|
const secretTargetRegistryEntries = [
|
|
4
4
|
{
|
|
@@ -72,16 +72,34 @@ function collectRuntimeConfigAssignments(params) {
|
|
|
72
72
|
const resolved = getChannelSurface(params.config, "feishu");
|
|
73
73
|
if (!resolved) return;
|
|
74
74
|
const { channel: feishu, surface } = resolved;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
const topLevelAppSecretActive = surface.channelEnabled && hasConfiguredSecretInputValue(feishu.appId, params.defaults) && hasConfiguredSecretInputValue(feishu.appSecret, params.defaults) || isBaseFieldActiveForChannelSurface(surface, "appSecret");
|
|
76
|
+
collectSecretInputAssignment({
|
|
77
|
+
value: feishu.appSecret,
|
|
78
|
+
path: "channels.feishu.appSecret",
|
|
79
|
+
expected: "string",
|
|
80
80
|
defaults: params.defaults,
|
|
81
81
|
context: params.context,
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
active: topLevelAppSecretActive,
|
|
83
|
+
inactiveReason: "no enabled account inherits this top-level Feishu appSecret.",
|
|
84
|
+
apply: (value) => {
|
|
85
|
+
feishu.appSecret = value;
|
|
86
|
+
}
|
|
84
87
|
});
|
|
88
|
+
if (surface.hasExplicitAccounts) for (const { accountId, account, enabled } of surface.accounts) {
|
|
89
|
+
if (!hasOwnProperty(account, "appSecret")) continue;
|
|
90
|
+
collectSecretInputAssignment({
|
|
91
|
+
value: account.appSecret,
|
|
92
|
+
path: `channels.feishu.accounts.${accountId}.appSecret`,
|
|
93
|
+
expected: "string",
|
|
94
|
+
defaults: params.defaults,
|
|
95
|
+
context: params.context,
|
|
96
|
+
active: enabled,
|
|
97
|
+
inactiveReason: "Feishu account is disabled.",
|
|
98
|
+
apply: (value) => {
|
|
99
|
+
account.appSecret = value;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
85
103
|
const baseConnectionMode = normalizeSecretStringValue(feishu.connectionMode) === "webhook" ? "webhook" : "websocket";
|
|
86
104
|
const resolveAccountMode = (account) => hasOwnProperty(account, "connectionMode") ? normalizeSecretStringValue(account.connectionMode) : baseConnectionMode;
|
|
87
105
|
collectConditionalChannelFieldAssignments({
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-
|
|
1
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-DLaBl9m4.js";
|
|
2
2
|
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|
|
@@ -15,6 +15,29 @@ import { Readable } from "node:stream";
|
|
|
15
15
|
import { saveMediaBuffer, saveMediaStream } from "openclaw/plugin-sdk/media-store";
|
|
16
16
|
import { resolvePreferredOpenClawTmpDir, withTempDownloadPath, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
17
17
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
18
|
+
//#region extensions/feishu/src/identity-header.ts
|
|
19
|
+
const emojiSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
20
|
+
const keycapEmojiPattern = /^[0-9#*]\uFE0F?\u20E3$/u;
|
|
21
|
+
const emojiLikeSegmentPattern = /[\p{Emoji_Presentation}\p{Extended_Pictographic}\p{Regional_Indicator}]/u;
|
|
22
|
+
function splitGraphemes(input) {
|
|
23
|
+
if (!emojiSegmenter) return Array.from(input);
|
|
24
|
+
return Array.from(emojiSegmenter.segment(input), (segment) => segment.segment);
|
|
25
|
+
}
|
|
26
|
+
function isEmojiSegment(segment) {
|
|
27
|
+
return keycapEmojiPattern.test(segment) || emojiLikeSegmentPattern.test(segment);
|
|
28
|
+
}
|
|
29
|
+
function resolveFeishuIdentityEmoji(raw) {
|
|
30
|
+
const trimmed = raw?.trim();
|
|
31
|
+
if (!trimmed) return;
|
|
32
|
+
return splitGraphemes(trimmed).filter(isEmojiSegment).join("") || void 0;
|
|
33
|
+
}
|
|
34
|
+
function resolveFeishuIdentityHeaderTitle(identity) {
|
|
35
|
+
if (!identity) return "";
|
|
36
|
+
const name = identity.name?.trim() ?? "";
|
|
37
|
+
const emoji = resolveFeishuIdentityEmoji(identity.emoji);
|
|
38
|
+
return (emoji ? `${emoji} ${name}` : name).trim();
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
18
41
|
//#region extensions/feishu/src/external-keys.ts
|
|
19
42
|
const CONTROL_CHARS_RE = /\p{Cc}/u;
|
|
20
43
|
const MAX_EXTERNAL_KEY_LENGTH = 512;
|
|
@@ -478,12 +501,14 @@ async function prepareFeishuVoiceMedia(params) {
|
|
|
478
501
|
return params;
|
|
479
502
|
}
|
|
480
503
|
}
|
|
481
|
-
async function
|
|
504
|
+
async function probeMediaDurationMs(params) {
|
|
482
505
|
try {
|
|
483
506
|
return await withTempWorkspace({
|
|
484
507
|
rootDir: resolvePreferredOpenClawTmpDir(),
|
|
485
|
-
prefix: "feishu-
|
|
508
|
+
prefix: "feishu-media-probe-"
|
|
486
509
|
}, async (workspace) => {
|
|
510
|
+
const ext = normalizeLowercaseStringOrEmpty(path.extname(params.fileName));
|
|
511
|
+
const inferredExt = ext && ext.length <= 12 ? ext : mediaKindFromMime(params.contentType) === "video" ? ".mp4" : ".ogg";
|
|
487
512
|
const stdout = await runFfprobe([
|
|
488
513
|
"-v",
|
|
489
514
|
"error",
|
|
@@ -491,17 +516,21 @@ async function probeAudioDurationMs(buffer) {
|
|
|
491
516
|
"format=duration",
|
|
492
517
|
"-of",
|
|
493
518
|
"csv=p=0",
|
|
494
|
-
await workspace.write(
|
|
519
|
+
await workspace.write(`input${inferredExt}`, params.buffer)
|
|
495
520
|
], { timeoutMs: 5e3 });
|
|
496
521
|
const seconds = Number.parseFloat(stdout.trim());
|
|
497
522
|
if (!Number.isFinite(seconds) || seconds <= 0) return;
|
|
498
523
|
return Math.max(1, Math.round(seconds * 1e3));
|
|
499
524
|
});
|
|
500
525
|
} catch (err) {
|
|
501
|
-
console.warn("[feishu] failed to probe
|
|
526
|
+
console.warn("[feishu] failed to probe media duration; upload will omit it:", err);
|
|
502
527
|
return;
|
|
503
528
|
}
|
|
504
529
|
}
|
|
530
|
+
async function maybeProbeUploadDurationMs(params) {
|
|
531
|
+
if (params.msgType !== "audio" && params.msgType !== "media") return;
|
|
532
|
+
return await probeMediaDurationMs(params);
|
|
533
|
+
}
|
|
505
534
|
/**
|
|
506
535
|
* Upload and send media (image or file) from URL, local path, or buffer.
|
|
507
536
|
* When mediaUrl is a local path, mediaLocalRoots (from core outbound context)
|
|
@@ -563,7 +592,12 @@ async function sendMediaFeishu(params) {
|
|
|
563
592
|
...voiceIntentDegradedToFile ? { voiceIntentDegradedToFile: true } : {}
|
|
564
593
|
};
|
|
565
594
|
}
|
|
566
|
-
const durationMs =
|
|
595
|
+
const durationMs = await maybeProbeUploadDurationMs({
|
|
596
|
+
buffer,
|
|
597
|
+
fileName: name,
|
|
598
|
+
contentType,
|
|
599
|
+
msgType: routing.msgType
|
|
600
|
+
});
|
|
567
601
|
const { fileKey } = await uploadFileFeishu({
|
|
568
602
|
cfg,
|
|
569
603
|
file: buffer,
|
|
@@ -1242,4 +1276,4 @@ async function sendMarkdownCardFeishu(params) {
|
|
|
1242
1276
|
});
|
|
1243
1277
|
}
|
|
1244
1278
|
//#endregion
|
|
1245
|
-
export { normalizeFeishuExternalKey as _, sendCardFeishu as a, sendStructuredCardFeishu as c, isFeishuBroadcastMention as d, isMentionForwardRequest as f, shouldSuppressFeishuTextForVoiceMedia as g, sendMediaFeishu as h, resolveFeishuCardTemplate as i, parsePostContent as l, saveMessageResourceFeishu as m, getMessageFeishu as n, sendMarkdownCardFeishu as o, isFeishuGroupChatType as p, listFeishuThreadMessages as r, sendMessageFeishu as s, editMessageFeishu as t, extractMentionTargets as u };
|
|
1279
|
+
export { normalizeFeishuExternalKey as _, sendCardFeishu as a, sendStructuredCardFeishu as c, isFeishuBroadcastMention as d, isMentionForwardRequest as f, shouldSuppressFeishuTextForVoiceMedia as g, sendMediaFeishu as h, resolveFeishuCardTemplate as i, parsePostContent as l, saveMessageResourceFeishu as m, getMessageFeishu as n, sendMarkdownCardFeishu as o, isFeishuGroupChatType as p, listFeishuThreadMessages as r, sendMessageFeishu as s, editMessageFeishu as t, extractMentionTargets as u, resolveFeishuIdentityEmoji as v, resolveFeishuIdentityHeaderTitle as y };
|
package/dist/setup-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-
|
|
1
|
+
import { i as feishuSetupAdapter, n as feishuSetupWizard, t as feishuPlugin } from "./channel-Bwm5rvHg.js";
|
|
2
2
|
export { feishuPlugin, feishuSetupAdapter, feishuSetupWizard };
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
1
2
|
//#region extensions/feishu/subagent-hooks-api.ts
|
|
2
|
-
|
|
3
|
-
function loadFeishuSubagentHooksModule() {
|
|
4
|
-
feishuSubagentHooksPromise ??= import("./subagent-hooks-1pqt5tAA.js").then((n) => n.i);
|
|
5
|
-
return feishuSubagentHooksPromise;
|
|
6
|
-
}
|
|
3
|
+
const loadFeishuSubagentHooksModule = createLazyRuntimeModule(() => import("./subagent-hooks-1pqt5tAA.js").then((n) => n.i));
|
|
7
4
|
function registerFeishuSubagentHooks(api) {
|
|
8
5
|
api.on("subagent_delivery_target", async (event) => {
|
|
9
6
|
const { handleFeishuSubagentDeliveryTarget } = await loadFeishuSubagentHooksModule();
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/feishu",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.7.1-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/feishu",
|
|
9
|
-
"version": "2026.
|
|
9
|
+
"version": "2026.7.1-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@larksuiteoapi/node-sdk": "1.66.0",
|
|
12
12
|
"typebox": "1.1.39",
|
|
13
13
|
"zod": "4.4.3"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.
|
|
16
|
+
"openclaw": ">=2026.7.1-beta.2"
|
|
17
17
|
},
|
|
18
18
|
"peerDependenciesMeta": {
|
|
19
19
|
"openclaw": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/feishu",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.7.1-beta.2",
|
|
4
4
|
"description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"zod": "4.4.3"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.
|
|
16
|
+
"openclaw": ">=2026.7.1-beta.2"
|
|
17
17
|
},
|
|
18
18
|
"peerDependenciesMeta": {
|
|
19
19
|
"openclaw": {
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"minHostVersion": ">=2026.5.29"
|
|
48
48
|
},
|
|
49
49
|
"compat": {
|
|
50
|
-
"pluginApi": ">=2026.
|
|
50
|
+
"pluginApi": ">=2026.7.1-beta.2"
|
|
51
51
|
},
|
|
52
52
|
"build": {
|
|
53
|
-
"openclawVersion": "2026.
|
|
53
|
+
"openclawVersion": "2026.7.1-beta.2"
|
|
54
54
|
},
|
|
55
55
|
"release": {
|
|
56
56
|
"publishToClawHub": true,
|