@openclaw/feishu 2026.9.8 → 2026.10.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/.setup/{channel-DV4hM2Uf.mjs → channel-CX62T71S.mjs} +146 -245
- package/dist/.setup/{channel.runtime-CXQcH5zZ.mjs → channel.runtime-COiaq-Rv.mjs} +6 -12
- package/dist/.setup/{chat-D8MlFAZi.mjs → chat-BdyvImsY.mjs} +6 -9
- package/dist/.setup/{client-BYG-_IZl.mjs → client-BsBVWJzN.mjs} +1 -1
- package/dist/.setup/{doctor-contract-3XC0vbIw.mjs → doctor-contract-B1B9ogdd.mjs} +212 -27
- package/dist/.setup/{monitor-D_rsHBZ6.mjs → monitor-7DvwUs4Y.mjs} +5 -6
- package/dist/.setup/{monitor.account-DvvY7i6k.mjs → monitor.account-7xVu7XWY.mjs} +190 -393
- package/dist/.setup/{probe-_ViqSi0j.mjs → probe-B9o7iey6.mjs} +13 -39
- package/dist/.setup/{reply-delivery-result-COAjaukc.mjs → reply-delivery-result-Bt-BWBEA.mjs} +151 -297
- package/dist/.setup/{setup-api-C4S5I3ac.mjs → setup-api-DmzX9S01.mjs} +1 -1
- package/dist/.setup/{subagent-hooks-BaFoMu8W.mjs → subagent-hooks-CUXg0pC-.mjs} +5 -11
- package/dist/.setup/{thread-bindings-EdLXPXzw.mjs → thread-bindings-jW2x5VuN.mjs} +23 -41
- package/dist/api.js +234 -297
- package/dist/channel-plugin-api.js +1 -1
- package/dist/doctor-contract-api.js +2 -2
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/setup-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/subagent-hooks-api.js +1 -1
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +95 -0
- package/node_modules/@openclaw/fs-safe/README.md +70 -379
- package/node_modules/@openclaw/fs-safe/dist/absolute-path.js +35 -51
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-input.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +9 -10
- package/node_modules/@openclaw/fs-safe/dist/archive.js +2 -5
- package/node_modules/@openclaw/fs-safe/dist/atomic-io.d.ts +51 -0
- package/node_modules/@openclaw/fs-safe/dist/atomic-io.js +242 -0
- package/node_modules/@openclaw/fs-safe/dist/config.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/config.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/copy-tree-portable.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/create.js +12 -5
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +11 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +4 -7
- package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.d.ts +55 -0
- package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/entry-publication.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/entry-publication.js +262 -0
- package/node_modules/@openclaw/fs-safe/dist/exclusive-create.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/exclusive-create.js +22 -0
- package/node_modules/@openclaw/fs-safe/dist/file-cleanup.d.ts +1 -6
- package/node_modules/@openclaw/fs-safe/dist/file-cleanup.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/file-identity.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-mutation.js +9 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root.js +4 -6
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-stale-admission.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +8 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.js +20 -18
- package/node_modules/@openclaw/fs-safe/dist/file-store.js +4 -10
- package/node_modules/@openclaw/fs-safe/dist/fs.d.ts +2 -10
- package/node_modules/@openclaw/fs-safe/dist/fs.js +2 -10
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +3 -4
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +6 -18
- package/node_modules/@openclaw/fs-safe/dist/guest-dispatch-python.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +0 -2
- package/node_modules/@openclaw/fs-safe/dist/guest.js +3 -9
- package/node_modules/@openclaw/fs-safe/dist/index.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/index.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.js +1 -5
- package/node_modules/@openclaw/fs-safe/dist/json.js +19 -37
- package/node_modules/@openclaw/fs-safe/dist/move-path.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/mutation-authority.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/mutation-authority.js +9 -1
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +47 -2
- package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +1 -9
- package/node_modules/@openclaw/fs-safe/dist/native-config.js +6 -40
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.js +5 -2
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +11 -316
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.d.ts +7 -7
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.js +28 -175
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.js +418 -0
- package/node_modules/@openclaw/fs-safe/dist/native-rename-outcome.js +9 -4
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +17 -13
- package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.js +6 -24
- package/node_modules/@openclaw/fs-safe/dist/native.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/path-case.js +10 -9
- package/node_modules/@openclaw/fs-safe/dist/path-scope-lexical.js +4 -1
- package/node_modules/@openclaw/fs-safe/dist/path-segment-route.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/path-segment-route.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/path.js +4 -1
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.js +1 -3
- package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +9 -10
- package/node_modules/@openclaw/fs-safe/dist/private-producer-handoff.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/publish-file.js +4 -3
- package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.d.ts +3 -4
- package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.js +18 -32
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +5 -17
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +92 -230
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.d.ts +4 -15
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.js +22 -63
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +9 -34
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +78 -83
- package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.d.ts +18 -20
- package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.js +64 -98
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +16 -33
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +61 -200
- package/node_modules/@openclaw/fs-safe/dist/replace-file-types.d.ts +1 -6
- package/node_modules/@openclaw/fs-safe/dist/replace-file.js +76 -216
- package/node_modules/@openclaw/fs-safe/dist/root-boundary.js +14 -24
- package/node_modules/@openclaw/fs-safe/dist/root-context.d.ts +1 -4
- package/node_modules/@openclaw/fs-safe/dist/root-context.js +4 -19
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.d.ts +52 -0
- package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +350 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +35 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +2 -27
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +31 -28
- package/node_modules/@openclaw/fs-safe/dist/root-directory.js +1 -4
- package/node_modules/@openclaw/fs-safe/dist/root-errors.js +34 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.js +9 -21
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +105 -37
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.d.ts +7 -2
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +67 -38
- package/node_modules/@openclaw/fs-safe/dist/root-observed-path.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/root-observed-path.js +0 -2
- package/node_modules/@openclaw/fs-safe/dist/root-options.d.ts +2 -3
- package/node_modules/@openclaw/fs-safe/dist/root-path-existing.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/root-path-stat.js +68 -85
- package/node_modules/@openclaw/fs-safe/dist/root-path.js +6 -1
- package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/root-paths.js +4 -9
- package/node_modules/@openclaw/fs-safe/dist/root-remove-native.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/root-remove-native.js +311 -0
- package/node_modules/@openclaw/fs-safe/dist/root-remove.d.ts +11 -0
- package/node_modules/@openclaw/fs-safe/dist/root-remove.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +2 -2
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +1 -3
- package/node_modules/@openclaw/fs-safe/dist/root-write-admission.d.ts +3 -3
- package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +8 -10
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +0 -4
- package/node_modules/@openclaw/fs-safe/dist/secret-file.js +12 -9
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.d.ts +0 -2
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-temp.js +7 -4
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +13 -6
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +0 -3
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +5 -23
- package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.js +11 -6
- package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.js +1 -8
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +2 -9
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +1 -6
- package/node_modules/@openclaw/fs-safe/dist/trash.js +6 -2
- package/node_modules/@openclaw/fs-safe/dist/walk.js +100 -46
- package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +235 -19
- package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +21 -2
- package/node_modules/@openclaw/fs-safe/dist/watch-native.js +21 -3
- package/node_modules/@openclaw/fs-safe/dist/watch-rescan.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-rescan.js +111 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +27 -4
- package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/watch.js +131 -40
- package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.js +24 -6
- package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.js +51 -0
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +4 -0
- package/node_modules/@openclaw/fs-safe/docs/atomic.md +4 -1
- package/node_modules/@openclaw/fs-safe/docs/config.md +6 -14
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +4 -14
- package/node_modules/@openclaw/fs-safe/docs/durability.md +6 -29
- package/node_modules/@openclaw/fs-safe/docs/entry-publication.md +146 -0
- package/node_modules/@openclaw/fs-safe/docs/errors.md +16 -0
- package/node_modules/@openclaw/fs-safe/docs/file-store.md +28 -5
- package/node_modules/@openclaw/fs-safe/docs/index.md +2 -31
- package/node_modules/@openclaw/fs-safe/docs/install.md +10 -31
- package/node_modules/@openclaw/fs-safe/docs/json.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/local-roots.md +0 -1
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +12 -12
- package/node_modules/@openclaw/fs-safe/docs/native-helper.md +35 -96
- package/node_modules/@openclaw/fs-safe/docs/native.md +22 -20
- package/node_modules/@openclaw/fs-safe/docs/path.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/permissions.md +1 -2
- package/node_modules/@openclaw/fs-safe/docs/public-api.md +1 -2
- package/node_modules/@openclaw/fs-safe/docs/reading.md +1 -2
- package/node_modules/@openclaw/fs-safe/docs/root.md +26 -184
- package/node_modules/@openclaw/fs-safe/docs/secret-file.md +1 -1
- package/node_modules/@openclaw/fs-safe/docs/security-model.md +115 -3
- package/node_modules/@openclaw/fs-safe/docs/store.md +2 -2
- package/node_modules/@openclaw/fs-safe/docs/temp.md +29 -65
- package/node_modules/@openclaw/fs-safe/docs/testing.md +90 -58
- package/node_modules/@openclaw/fs-safe/docs/types.md +3 -16
- package/node_modules/@openclaw/fs-safe/docs/walk.md +33 -5
- package/node_modules/@openclaw/fs-safe/docs/watch.md +96 -14
- package/node_modules/@openclaw/fs-safe/docs/writing.md +172 -16
- package/node_modules/@openclaw/fs-safe/package.json +10 -10
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
- package/package.json +5 -5
- package/skills/feishu-wiki/SKILL.md +1 -1
- package/dist/.setup/accounts-wRqItHug.mjs +0 -206
- package/node_modules/@openclaw/fs-safe/dist/watch-alias.d.ts +0 -6
- package/node_modules/@openclaw/fs-safe/dist/watch-alias.js +0 -88
- package/node_modules/@openclaw/fs-safe/docs/mutation-policy-proof.md +0 -69
- package/node_modules/@openclaw/fs-safe/docs/private-file-store.md +0 -68
- package/node_modules/@openclaw/fs-safe/docs/test-hooks.md +0 -110
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as resolveFeishuRuntimeAccount, s as resolveFeishuAccount } from "./accounts-wRqItHug.mjs";
|
|
1
|
+
import { h as resolveFeishuRuntimeAccount, m as resolveFeishuAccount, o as normalizeFeishuWebhookPath, s as normalizeFeishuExternalKey } from "./doctor-contract-B1B9ogdd.mjs";
|
|
3
2
|
import { o as resolveConfiguredFeishuGroupSessionScope, t as buildFeishuConversationId, u as resolveReceiveIdType } from "./conversation-id-C1ofUfU8.mjs";
|
|
4
|
-
import { c as resolveFeishuLegacyWebhookListener, l as gateway_config_runtime_exports, s as describeFeishuWebhookPathConflict } from "./channel-
|
|
5
|
-
import { A as sendMessageFeishu, B as parsePostContent, D as getMessageFeishu, Dt as
|
|
3
|
+
import { c as resolveFeishuLegacyWebhookListener, l as gateway_config_runtime_exports, s as describeFeishuWebhookPathConflict } from "./channel-CX62T71S.mjs";
|
|
4
|
+
import { A as sendMessageFeishu, At as resolveFeishuGroupSenderActivationIngressAccess, B as parsePostContent, D as getMessageFeishu, Dt as resolveFeishuDmIngressAccess, Et as normalizeFeishuAllowEntry, F as isFeishuBroadcastMention, G as deliverCommentThreadText, H as buildFeishuMediaFallbackText, I as isMentionForwardRequest, It as createFeishuCardInteractionEnvelope, L as isFeishuGroupChatType, Lt as decodeFeishuCardAction, Mt as resolveFeishuReplyPolicy, N as formatFeishuMediaContent, Nt as normalizeFeishuChatType, O as listFeishuThreadMessages, Ot as resolveFeishuGroupConfig, P as extractMentionTargets, Pt as resolveFeishuChatType, R as normalizeFeishuEventChatType, S as sendMediaFeishu, T as chunkFeishuCardMarkdown, Tt as hasExplicitFeishuGroupConfig, U as resolveFeishuIdentityEmoji, a as shouldSendNoVisibleReplyFallback, at as requestFeishuApi, b as withinCardTableLimit, d as consumeFeishuPresentationFallbackMarker, et as createCommentTypingReactionLifecycle, ft as chunkFeishuPostMarkdown, ht as shouldUseFeishuCard, i as noVisibleFeishuReplyDelivery, it as parseCommentContentElements, j as sendStructuredCardFeishu, k as sendCardFeishu, kt as resolveFeishuGroupConversationIngressAccess, n as createFeishuReplyDeliveryResult, nt as extractReplyText, ot as buildFeishuCommentTarget, pt as materializeFeishuPostMarkdownSoftBreaks, r as mergeFeishuReplyDeliveryResults, st as normalizeCommentFileType, t as createFeishuPartialReplyDeliveryError, tt as encodeQuery, u as buildFeishuPresentationFallback, ut as resolveFeishuCardTemplate, v as renderFeishuReplyPayload, w as shouldSuppressFeishuTextForVoiceMedia, x as saveMessageResourceFeishu, y as resolveFeishuRichReply, z as parseInteractiveCardContent } from "./reply-delivery-result-Bt-BWBEA.mjs";
|
|
6
5
|
import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.mjs";
|
|
7
|
-
import { a as getFeishuUserAgent, f as resolveConfiguredHttpTimeoutMs, i as createFeishuWSClient, n as createEventDispatcher, r as createFeishuClient } from "./client-
|
|
8
|
-
import { r as getChatInfo } from "./chat-
|
|
9
|
-
import { t as createFeishuThreadBindingManager } from "./thread-bindings-
|
|
6
|
+
import { a as getFeishuUserAgent, f as resolveConfiguredHttpTimeoutMs, i as createFeishuWSClient, n as createEventDispatcher, r as createFeishuClient } from "./client-BsBVWJzN.mjs";
|
|
7
|
+
import { r as getChatInfo } from "./chat-BdyvImsY.mjs";
|
|
8
|
+
import { t as createFeishuThreadBindingManager } from "./thread-bindings-jW2x5VuN.mjs";
|
|
10
9
|
import { evaluateSupplementalContextVisibility, normalizeAgentId as normalizeAgentId$1, resolveChannelContextVisibilityMode } from "../runtime-api.js";
|
|
11
10
|
import { t as readFeishuJsonResponse } from "./json-response-DXajw_FU.mjs";
|
|
12
|
-
import { a as waitForAbortableDelay, i as raceWithTimeoutAndAbort } from "./probe-
|
|
13
|
-
import { t as fetchBotIdentityForMonitor } from "./monitor-
|
|
11
|
+
import { a as waitForAbortableDelay, i as raceWithTimeoutAndAbort } from "./probe-B9o7iey6.mjs";
|
|
12
|
+
import { t as fetchBotIdentityForMonitor } from "./monitor-7DvwUs4Y.mjs";
|
|
14
13
|
import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
15
14
|
import { DEFAULT_INGRESS_ADOPTION_STALL_MS, bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, createReplyPrefixContext, formatChannelProgressDraftLineForEntry, resolveAgentOutboundIdentity, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
|
|
16
15
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
17
16
|
import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
|
|
18
|
-
import { collectErrorGraphCandidates,
|
|
17
|
+
import { collectErrorGraphCandidates, formatErrorMessage, toStringifiedError } from "openclaw/plugin-sdk/error-runtime";
|
|
19
18
|
import { asDateTimestampMs, isFutureDateTimestampMs, parseStrictNonNegativeInteger, resolveDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveExpiresAtMsFromDurationSeconds, resolvePromptHistoryLimit, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
20
19
|
import { asBoolean, asNullableRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeNullableString, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeTrimmedStringList, readStringValue, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
21
20
|
import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
|
|
@@ -37,20 +36,19 @@ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
|
37
36
|
import { escapeRegExp, sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
38
37
|
import * as crypto$1 from "node:crypto";
|
|
39
38
|
import crypto, { createHash } from "node:crypto";
|
|
40
|
-
import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
41
39
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
40
|
+
import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
|
|
41
|
+
import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
42
42
|
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
43
43
|
import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
|
|
44
44
|
import { formatReasoningMessage, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
45
45
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
46
46
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
47
|
-
import
|
|
48
|
-
import { WEBHOOK_RATE_LIMIT_DEFAULTS, applyBasicWebhookRequestGuards, createFixedWindowRateLimiter, createWebhookAnomalyTracker, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
|
|
47
|
+
import { WEBHOOK_RATE_LIMIT_DEFAULTS, applyBasicWebhookRequestGuards, createFixedWindowRateLimiter, createWebhookAnomalyTracker, getWebhookLegacyListener, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
|
|
49
48
|
import { createRuntimeConfigReader } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
50
49
|
import { channelBlockedPatch, channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
51
50
|
import { createWebhookInFlightLimiter, readWebhookBodyOrReject, sendHttpRequestRejection } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
52
51
|
import { canonicalizeWebhookRouteKey, registerPluginHttpRoute, registerWebhookTarget, resolveSingleWebhookTarget } from "openclaw/plugin-sdk/webhook-targets";
|
|
53
|
-
import { createServer } from "node:http";
|
|
54
52
|
import { isAbortRequestText, isBtwRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
|
|
55
53
|
//#region src/channels/mention-gating.ts
|
|
56
54
|
function resolveBotThreadMentionPolicy(params) {
|
|
@@ -199,9 +197,6 @@ function createFeishuBroadcastIngressSettlement(params) {
|
|
|
199
197
|
status: "pending"
|
|
200
198
|
};
|
|
201
199
|
lanes.add(lane);
|
|
202
|
-
const releaseLane = (error) => {
|
|
203
|
-
lane.replayClaim?.release({ error });
|
|
204
|
-
};
|
|
205
200
|
return {
|
|
206
201
|
lifecycle: {
|
|
207
202
|
abortSignal: params.lifecycle?.abortSignal ?? fallbackAbort.signal,
|
|
@@ -234,7 +229,7 @@ function createFeishuBroadcastIngressSettlement(params) {
|
|
|
234
229
|
onAbandoned: async () => {
|
|
235
230
|
if (lane.status === "completed" || lane.status === "failed" || lane.status === "abandoned") return;
|
|
236
231
|
lane.status = "abandoned";
|
|
237
|
-
|
|
232
|
+
lane.replayClaim?.release({ error: /* @__PURE__ */ new Error("feishu-broadcast-turn-abandoned") });
|
|
238
233
|
await maybeSettle();
|
|
239
234
|
}
|
|
240
235
|
},
|
|
@@ -243,13 +238,13 @@ function createFeishuBroadcastIngressSettlement(params) {
|
|
|
243
238
|
const error = /* @__PURE__ */ new Error(dispatched ? "feishu broadcast dispatch returned before turn adoption" : "feishu broadcast lane was not dispatched");
|
|
244
239
|
lane.status = "failed";
|
|
245
240
|
failures.push(error);
|
|
246
|
-
|
|
241
|
+
lane.replayClaim?.release({ error });
|
|
247
242
|
},
|
|
248
243
|
onDispatchFailed: async (error) => {
|
|
249
244
|
failures.push(error);
|
|
250
245
|
if (lane.status !== "completed") {
|
|
251
246
|
lane.status = "failed";
|
|
252
|
-
|
|
247
|
+
lane.replayClaim?.release({ error });
|
|
253
248
|
}
|
|
254
249
|
await maybeSettle();
|
|
255
250
|
}
|
|
@@ -343,9 +338,10 @@ function parseMessageContent(content, messageType) {
|
|
|
343
338
|
if (messageType === "share_chat") {
|
|
344
339
|
if (parsed && typeof parsed === "object") {
|
|
345
340
|
const share = parsed;
|
|
346
|
-
|
|
347
|
-
if (
|
|
348
|
-
|
|
341
|
+
const text = normalizeOptionalString(share.body) ?? normalizeOptionalString(share.summary);
|
|
342
|
+
if (text) return text;
|
|
343
|
+
const sharedChatId = normalizeOptionalString(share.share_chat_id);
|
|
344
|
+
if (sharedChatId) return `[Forwarded message: ${sharedChatId}]`;
|
|
349
345
|
}
|
|
350
346
|
return "[Forwarded message]";
|
|
351
347
|
}
|
|
@@ -447,7 +443,7 @@ async function resolveFeishuMediaList(params) {
|
|
|
447
443
|
key: attachment.key,
|
|
448
444
|
type: attachment.kind,
|
|
449
445
|
fileName: attachment.kind === "file" ? attachment.fileName : void 0,
|
|
450
|
-
kind: attachment.kind === "image" ? "image" : "video",
|
|
446
|
+
kind: attachment.kind === "image" ? "image" : attachment.origin === "top-level" ? "document" : "video",
|
|
451
447
|
label: `embedded ${attachment.kind} ${attachment.key}`
|
|
452
448
|
});
|
|
453
449
|
}
|
|
@@ -897,7 +893,7 @@ function parseContentRecord(content) {
|
|
|
897
893
|
}
|
|
898
894
|
}
|
|
899
895
|
function resolvePostMediaParts(content) {
|
|
900
|
-
const { attachments } = parsePostContent(content);
|
|
896
|
+
const { attachments } = parsePostContent(content, { includeTopLevelFiles: false });
|
|
901
897
|
return ["image", "file"].flatMap((kind) => attachments.filter((attachment) => attachment.kind === kind).map((attachment) => `${kind}_key:${attachment.key}`));
|
|
902
898
|
}
|
|
903
899
|
function resolveMessageMediaParts(messageType, content) {
|
|
@@ -974,7 +970,7 @@ function resolveDynamicAgentConfig(cfg, accountId) {
|
|
|
974
970
|
}
|
|
975
971
|
function isAtDynamicAgentLimit(cfg, dynamicCfg) {
|
|
976
972
|
if (dynamicCfg.maxAgents === void 0) return false;
|
|
977
|
-
return (cfg.agents?.
|
|
973
|
+
return Object.keys(cfg.agents?.entries ?? {}).filter((id) => id.startsWith("feishu-")).length >= dynamicCfg.maxAgents;
|
|
978
974
|
}
|
|
979
975
|
function resolveDynamicAgentId(accountId, senderOpenId) {
|
|
980
976
|
if (accountId === "default") return `feishu-${senderOpenId}`;
|
|
@@ -1014,7 +1010,7 @@ async function maybeCreateDynamicAgent(params) {
|
|
|
1014
1010
|
};
|
|
1015
1011
|
}
|
|
1016
1012
|
const agentId = resolveDynamicAgentId(accountId, senderOpenId);
|
|
1017
|
-
if (!(currentCfg.agents?.
|
|
1013
|
+
if (!Object.hasOwn(currentCfg.agents?.entries ?? {}, agentId) && isAtDynamicAgentLimit(currentCfg, currentDynamicCfg)) {
|
|
1018
1014
|
log(`feishu: maxAgents limit (${currentDynamicCfg.maxAgents}) reached, not creating agent for ${senderOpenId}`);
|
|
1019
1015
|
return {
|
|
1020
1016
|
created: false,
|
|
@@ -1037,7 +1033,7 @@ async function maybeCreateDynamicAgent(params) {
|
|
|
1037
1033
|
channelId: "feishu",
|
|
1038
1034
|
accountId
|
|
1039
1035
|
})) throw new DynamicAgentMutationSkipped(draft);
|
|
1040
|
-
const agentExists = (draft.agents?.
|
|
1036
|
+
const agentExists = Object.hasOwn(draft.agents?.entries ?? {}, agentId);
|
|
1041
1037
|
if (!agentExists && isAtDynamicAgentLimit(draft, dynamicCfg)) {
|
|
1042
1038
|
log(`feishu: maxAgents limit (${dynamicCfg.maxAgents}) reached, not creating agent for ${senderOpenId}`);
|
|
1043
1039
|
throw new DynamicAgentMutationSkipped(draft);
|
|
@@ -1055,11 +1051,13 @@ async function maybeCreateDynamicAgent(params) {
|
|
|
1055
1051
|
await fs.promises.mkdir(agentDir, { recursive: true });
|
|
1056
1052
|
draft.agents = {
|
|
1057
1053
|
...draft.agents,
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1054
|
+
entries: {
|
|
1055
|
+
...draft.agents?.entries,
|
|
1056
|
+
[agentId]: {
|
|
1057
|
+
workspace,
|
|
1058
|
+
agentDir
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1063
1061
|
};
|
|
1064
1062
|
} else log(`feishu: agent "${agentId}" exists, adding missing binding for ${senderOpenId}`);
|
|
1065
1063
|
draft.bindings = [...draft.bindings ?? [], {
|
|
@@ -1095,22 +1093,14 @@ async function maybeCreateDynamicAgent(params) {
|
|
|
1095
1093
|
agentId: committed.result?.agentId
|
|
1096
1094
|
};
|
|
1097
1095
|
}
|
|
1098
|
-
/**
|
|
1099
|
-
* Resolve a path that may start with ~ to the user's home directory.
|
|
1100
|
-
*/
|
|
1101
1096
|
function resolveUserPath(p) {
|
|
1102
1097
|
if (p.startsWith("~/")) return path.join(os.homedir(), p.slice(2));
|
|
1103
1098
|
return p;
|
|
1104
1099
|
}
|
|
1105
1100
|
//#endregion
|
|
1106
|
-
//#region extensions/feishu/src/agent-config.ts
|
|
1107
|
-
function resolveFeishuConfigReasoningDefault(cfg, agentId) {
|
|
1108
|
-
return resolveAgentConfig(cfg, agentId)?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault ?? "off";
|
|
1109
|
-
}
|
|
1110
|
-
//#endregion
|
|
1111
1101
|
//#region extensions/feishu/src/reasoning-preview.ts
|
|
1112
1102
|
function resolveFeishuReasoningPreviewEnabled(params) {
|
|
1113
|
-
const configDefault =
|
|
1103
|
+
const configDefault = resolveAgentConfig(params.cfg, params.agentId)?.reasoningDefault ?? params.cfg.agents?.defaults?.reasoningDefault ?? "off";
|
|
1114
1104
|
if (!params.sessionKey) return configDefault === "stream";
|
|
1115
1105
|
try {
|
|
1116
1106
|
const level = getSessionEntry({
|
|
@@ -1128,13 +1118,6 @@ function resolveFeishuReasoningPreviewEnabled(params) {
|
|
|
1128
1118
|
//#region extensions/feishu/src/reply-dispatcher-state.ts
|
|
1129
1119
|
const streamingStartBackoffUntilByAccount = /* @__PURE__ */ new Map();
|
|
1130
1120
|
//#endregion
|
|
1131
|
-
//#region extensions/feishu/src/streaming-card-send-mode.ts
|
|
1132
|
-
function resolveStreamingCardSendMode(options) {
|
|
1133
|
-
if (options?.replyToMessageId) return "reply";
|
|
1134
|
-
if (options?.rootId) return "root_create";
|
|
1135
|
-
return "create";
|
|
1136
|
-
}
|
|
1137
|
-
//#endregion
|
|
1138
1121
|
//#region extensions/feishu/src/streaming-card.ts
|
|
1139
1122
|
/** Provider finalization failed after a streaming card may already be visible. */
|
|
1140
1123
|
var FeishuStreamingFinalizationError = class extends Error {
|
|
@@ -1223,7 +1206,6 @@ async function getToken(creds, deps) {
|
|
|
1223
1206
|
return data.tenant_access_token;
|
|
1224
1207
|
}
|
|
1225
1208
|
function truncateSummary(text, max = 50) {
|
|
1226
|
-
if (!text) return "";
|
|
1227
1209
|
const clean = text.replace(/\n/g, " ").trim();
|
|
1228
1210
|
return clean.length <= max ? clean : sliceUtf16Safe(clean, 0, max - 3) + "...";
|
|
1229
1211
|
}
|
|
@@ -1242,7 +1224,6 @@ function mergeStreamingText(previousText, nextText) {
|
|
|
1242
1224
|
for (let overlap = maxOverlap; overlap > 0; overlap -= 1) if (previous.slice(-overlap) === next.slice(0, overlap)) return `${previous}${next.slice(overlap)}`;
|
|
1243
1225
|
return `${previous}${next}`;
|
|
1244
1226
|
}
|
|
1245
|
-
/** Streaming card session manager */
|
|
1246
1227
|
var FeishuStreamingSession = class {
|
|
1247
1228
|
constructor(client, creds, log, deps) {
|
|
1248
1229
|
this.state = null;
|
|
@@ -1336,24 +1317,21 @@ var FeishuStreamingSession = class {
|
|
|
1336
1317
|
type: "card",
|
|
1337
1318
|
data: { card_id: cardId }
|
|
1338
1319
|
});
|
|
1339
|
-
let sendRes;
|
|
1340
1320
|
const sendOptions = options ?? {};
|
|
1341
|
-
const
|
|
1342
|
-
if (sendMode === "reply") sendRes = await requestFeishuApi(() => this.client.im.message.reply({
|
|
1321
|
+
const sendRes = await requestFeishuApi(() => sendOptions.replyToMessageId ? this.client.im.message.reply({
|
|
1343
1322
|
path: { message_id: sendOptions.replyToMessageId },
|
|
1344
1323
|
data: {
|
|
1345
1324
|
msg_type: "interactive",
|
|
1346
1325
|
content: cardContent,
|
|
1347
1326
|
...sendOptions.replyInThread ? { reply_in_thread: true } : {}
|
|
1348
1327
|
}
|
|
1349
|
-
})
|
|
1350
|
-
else sendRes = await requestFeishuApi(() => this.client.im.message.create({
|
|
1328
|
+
}) : this.client.im.message.create({
|
|
1351
1329
|
params: { receive_id_type: receiveIdType },
|
|
1352
1330
|
data: {
|
|
1353
1331
|
receive_id: receiveId,
|
|
1354
1332
|
msg_type: "interactive",
|
|
1355
1333
|
content: cardContent,
|
|
1356
|
-
...
|
|
1334
|
+
...sendOptions.rootId ? { root_id: sendOptions.rootId } : {}
|
|
1357
1335
|
}
|
|
1358
1336
|
}), "Send card failed");
|
|
1359
1337
|
if (sendRes.code !== 0) throw new Error(`Send card failed: ${sendRes.msg}`);
|
|
@@ -1535,10 +1513,9 @@ function isFeishuBackoffError(err) {
|
|
|
1535
1513
|
const response = err.response;
|
|
1536
1514
|
if (response) {
|
|
1537
1515
|
if (response.status === 429) return true;
|
|
1538
|
-
if (
|
|
1516
|
+
if (getBackoffCodeFromResponse(response.data) !== void 0) return true;
|
|
1539
1517
|
}
|
|
1540
|
-
|
|
1541
|
-
return typeof code === "number" && FEISHU_BACKOFF_CODES.has(code);
|
|
1518
|
+
return getBackoffCodeFromResponse(err) !== void 0;
|
|
1542
1519
|
}
|
|
1543
1520
|
function getBackoffCodeFromResponse(response) {
|
|
1544
1521
|
if (typeof response !== "object" || response === null) return;
|
|
@@ -1628,8 +1605,7 @@ async function removeTypingIndicator(params) {
|
|
|
1628
1605
|
//#endregion
|
|
1629
1606
|
//#region extensions/feishu/src/reply-dispatcher.ts
|
|
1630
1607
|
function mergeStreamingFinalText(previousText, nextText, appendError) {
|
|
1631
|
-
if (!appendError || !previousText) return nextText;
|
|
1632
|
-
if (nextText.startsWith(previousText)) return nextText;
|
|
1608
|
+
if (!appendError || !previousText || nextText.startsWith(previousText)) return nextText;
|
|
1633
1609
|
if (previousText.endsWith(`\n\n${nextText}`)) return previousText;
|
|
1634
1610
|
return `${previousText}\n\n${nextText}`;
|
|
1635
1611
|
}
|
|
@@ -1656,7 +1632,6 @@ function normalizeEpochMs(timestamp) {
|
|
|
1656
1632
|
if (!Number.isFinite(timestamp) || timestamp === void 0 || timestamp <= 0) return;
|
|
1657
1633
|
return timestamp < MS_EPOCH_MIN ? timestamp * 1e3 : timestamp;
|
|
1658
1634
|
}
|
|
1659
|
-
/** Build a card header from agent identity config. */
|
|
1660
1635
|
function resolveCardHeader(agentId, identity) {
|
|
1661
1636
|
const name = identity?.name?.trim() || (agentId === "main" ? "" : agentId);
|
|
1662
1637
|
const emoji = resolveFeishuIdentityEmoji(identity?.emoji);
|
|
@@ -1667,7 +1642,6 @@ function resolveCardHeader(agentId, identity) {
|
|
|
1667
1642
|
template: identity?.theme ?? "blue"
|
|
1668
1643
|
};
|
|
1669
1644
|
}
|
|
1670
|
-
/** Build a card note footer from agent identity and model context. */
|
|
1671
1645
|
function resolveCardNote(agentId, identity, prefixCtx) {
|
|
1672
1646
|
const parts = [`Agent: ${identity?.name?.trim() || agentId}`];
|
|
1673
1647
|
if (prefixCtx.model) parts.push(`Model: ${prefixCtx.model}`);
|
|
@@ -1774,20 +1748,12 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1774
1748
|
let idleRequestedForReply = false;
|
|
1775
1749
|
let replyLifecycleStateInitialized = false;
|
|
1776
1750
|
const pendingStreamingDeliveries = [];
|
|
1777
|
-
const markVisibleReplySent = () => {
|
|
1778
|
-
visibleReplySent = true;
|
|
1779
|
-
};
|
|
1780
1751
|
const formatReasoningPrefix = (thinking) => {
|
|
1781
1752
|
if (!thinking) return "";
|
|
1782
1753
|
return `> 💭 **Thinking**\n${thinking.replace(/^(?:Reasoning:|Thinking\.{0,3})\s*/u, "").replace(/^_(.*)_$/gm, "$1").split("\n").map((line) => `> ${line}`).join("\n")}`;
|
|
1783
1754
|
};
|
|
1784
1755
|
const buildCombinedStreamText = (thinking, answer) => {
|
|
1785
|
-
|
|
1786
|
-
if (thinking) parts.push(formatReasoningPrefix(thinking));
|
|
1787
|
-
if (thinking && answer) parts.push("\n\n---\n\n");
|
|
1788
|
-
if (answer) parts.push(answer);
|
|
1789
|
-
if (statusLine) parts.push(parts.length > 0 ? `\n\n${statusLine}` : statusLine);
|
|
1790
|
-
return parts.join("");
|
|
1756
|
+
return [[thinking ? formatReasoningPrefix(thinking) : "", answer].filter(Boolean).join("\n\n---\n\n"), statusLine].filter(Boolean).join("\n\n");
|
|
1791
1757
|
};
|
|
1792
1758
|
const flushStreamingCardUpdate = (combined) => {
|
|
1793
1759
|
const session = streaming;
|
|
@@ -1915,7 +1881,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1915
1881
|
content: closed.content,
|
|
1916
1882
|
kind: "card"
|
|
1917
1883
|
});
|
|
1918
|
-
if (result.visibleReplySent)
|
|
1884
|
+
if (result.visibleReplySent) visibleReplySent = true;
|
|
1919
1885
|
if (disposition === "closed" && result.visibleReplySent && finalizedAnswerText && (finalizationError === void 0 || result.content === text)) deliveredFinalTexts.add(finalizedAnswerText);
|
|
1920
1886
|
if (finalizationError instanceof FeishuStreamingFinalizationError && result.visibleReplySent) finalizationError = createFeishuPartialReplyDeliveryError(finalizationError.cause ?? finalizationError, result);
|
|
1921
1887
|
}
|
|
@@ -1959,18 +1925,13 @@ function createFeishuReplyDispatcher(params) {
|
|
|
1959
1925
|
return closePromise;
|
|
1960
1926
|
};
|
|
1961
1927
|
const deferStreamingDelivery = (result, infoKind, ownerGeneration) => {
|
|
1962
|
-
|
|
1963
|
-
let rejectFinalization;
|
|
1964
|
-
const finalization = new Promise((resolve, reject) => {
|
|
1965
|
-
resolveFinalization = resolve;
|
|
1966
|
-
rejectFinalization = reject;
|
|
1967
|
-
});
|
|
1928
|
+
const { promise: finalization, resolve, reject } = createDeferred();
|
|
1968
1929
|
pendingStreamingDeliveries.push({
|
|
1969
1930
|
result,
|
|
1970
1931
|
...infoKind ? { infoKind } : {},
|
|
1971
1932
|
...ownerGeneration === void 0 ? {} : { streamingGeneration: ownerGeneration },
|
|
1972
|
-
resolve
|
|
1973
|
-
reject
|
|
1933
|
+
resolve,
|
|
1934
|
+
reject
|
|
1974
1935
|
});
|
|
1975
1936
|
if (idleRequestedForReply) queueIdleSideEffects().catch((error) => params.runtime.error?.(`feishu[${account.accountId}] late reply finalization failed: ${String(error)}`));
|
|
1976
1937
|
return {
|
|
@@ -2031,12 +1992,12 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2031
1992
|
});
|
|
2032
1993
|
results.push(result);
|
|
2033
1994
|
acceptedChunks.push(chunk);
|
|
2034
|
-
|
|
1995
|
+
visibleReplySent = true;
|
|
2035
1996
|
} catch (error) {
|
|
2036
1997
|
const acceptedChunk = isChannelPartialDeliveryError(error) ? error.deliveryResult : void 0;
|
|
2037
1998
|
if (acceptedChunk) {
|
|
2038
1999
|
acceptedChunks.push(acceptedChunk.content ?? chunk);
|
|
2039
|
-
|
|
2000
|
+
visibleReplySent = true;
|
|
2040
2001
|
}
|
|
2041
2002
|
throw createFeishuPartialReplyDeliveryError(error, {
|
|
2042
2003
|
...acceptedChunk,
|
|
@@ -2083,12 +2044,12 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2083
2044
|
visibleReplySent: true,
|
|
2084
2045
|
kind: result?.voiceIntentDegradedToFile ? "media" : void 0
|
|
2085
2046
|
}));
|
|
2086
|
-
|
|
2047
|
+
visibleReplySent = true;
|
|
2087
2048
|
if (result?.voiceIntentDegradedToFile && options?.fallbackText && !sentFallbackText) degradedVoiceFallbackText = options.fallbackText;
|
|
2088
2049
|
},
|
|
2089
2050
|
onError: options?.fallbackText === void 0 ? void 0 : async ({ error, mediaUrl }) => {
|
|
2090
2051
|
if (isChannelPartialDeliveryError(error)) {
|
|
2091
|
-
|
|
2052
|
+
visibleReplySent = true;
|
|
2092
2053
|
throw toStringifiedError(error);
|
|
2093
2054
|
}
|
|
2094
2055
|
const fallbackText = await buildFeishuMediaFallbackText({
|
|
@@ -2099,13 +2060,10 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2099
2060
|
results.push(await sendPostReply(fallbackText, "final"));
|
|
2100
2061
|
}
|
|
2101
2062
|
});
|
|
2102
|
-
if (degradedVoiceFallbackText && !sentFallbackText)
|
|
2103
|
-
sentFallbackText = true;
|
|
2104
|
-
results.push(await sendPostReply(degradedVoiceFallbackText, "final"));
|
|
2105
|
-
}
|
|
2063
|
+
if (degradedVoiceFallbackText && !sentFallbackText) results.push(await sendPostReply(degradedVoiceFallbackText, "final"));
|
|
2106
2064
|
} catch (error) {
|
|
2107
2065
|
const partial = isChannelPartialDeliveryError(error) ? error.deliveryResult : void 0;
|
|
2108
|
-
if (partial)
|
|
2066
|
+
if (partial) visibleReplySent = true;
|
|
2109
2067
|
throw createFeishuPartialReplyDeliveryError(error, mergeFeishuReplyDeliveryResults([...results, ...partial ? [partial] : []]));
|
|
2110
2068
|
}
|
|
2111
2069
|
return mergeFeishuReplyDeliveryResults(results);
|
|
@@ -2122,7 +2080,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2122
2080
|
text: NO_VISIBLE_REPLY_FALLBACK_TEXT,
|
|
2123
2081
|
...requiredMentionTargets?.length ? { mentions: requiredMentionTargets } : {}
|
|
2124
2082
|
});
|
|
2125
|
-
|
|
2083
|
+
visibleReplySent = true;
|
|
2126
2084
|
params.runtime.error?.(`feishu[${account.accountId}]: sent no-visible-reply fallback (${reason})`);
|
|
2127
2085
|
return true;
|
|
2128
2086
|
};
|
|
@@ -2139,12 +2097,6 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2139
2097
|
if (result) result.contentClaimed = true;
|
|
2140
2098
|
return result;
|
|
2141
2099
|
};
|
|
2142
|
-
const markClosedStreamingContentClaimed = (generation) => {
|
|
2143
|
-
if (generation !== void 0) {
|
|
2144
|
-
const settlement = closedStreamingSettlements.get(generation);
|
|
2145
|
-
if (settlement) settlement.contentClaimed = true;
|
|
2146
|
-
}
|
|
2147
|
-
};
|
|
2148
2100
|
const ensureVisibleStreamingDelivery = async (result, content, infoKind) => {
|
|
2149
2101
|
if (result?.visibleReplySent === true || !content?.trim()) return result;
|
|
2150
2102
|
return sendChunkedTextReply({
|
|
@@ -2164,7 +2116,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2164
2116
|
const closeOutcome = await closeStreaming();
|
|
2165
2117
|
const finalized = closeOutcome.result;
|
|
2166
2118
|
const ownsCurrentClose = (completion) => closeOutcome.generation !== void 0 && completion.streamingGeneration === closeOutcome.generation;
|
|
2167
|
-
if (completions.some((completion) => ownsCurrentClose(completion)))
|
|
2119
|
+
if (completions.some((completion) => ownsCurrentClose(completion))) claimClosedStreamingResult(closeOutcome.generation, void 0);
|
|
2168
2120
|
for (const completion of completions) {
|
|
2169
2121
|
const claimedSettlement = ownsCurrentClose(completion) ? {
|
|
2170
2122
|
disposition: closeOutcome.disposition,
|
|
@@ -2192,7 +2144,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2192
2144
|
continue;
|
|
2193
2145
|
}
|
|
2194
2146
|
const settledResult = mergeFeishuReplyDeliveryResults([...providerFinalized ? [providerFinalized] : [], completion.result], deliveryError === void 0 ? completion.result.content ?? providerFinalized?.content : providerFinalized?.content ?? completion.result.content);
|
|
2195
|
-
if (deliveryError !== void 0) completion.reject(createFeishuPartialReplyDeliveryError(isChannelPartialDeliveryError(deliveryError) && deliveryError instanceof Error
|
|
2147
|
+
if (deliveryError !== void 0) completion.reject(createFeishuPartialReplyDeliveryError(isChannelPartialDeliveryError(deliveryError) && deliveryError instanceof Error || deliveryError instanceof FeishuStreamingFinalizationError ? deliveryError.cause ?? deliveryError : deliveryError, settledResult));
|
|
2196
2148
|
else completion.resolve(settledResult);
|
|
2197
2149
|
}
|
|
2198
2150
|
if (closeOutcome.error !== void 0) throw toStringifiedError(closeOutcome.error);
|
|
@@ -2280,7 +2232,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2280
2232
|
};
|
|
2281
2233
|
const handleDeliveryError = async (error, info) => {
|
|
2282
2234
|
if (info.kind === "final") replyOutcome = { kind: "failed" };
|
|
2283
|
-
if (isChannelPartialDeliveryError(error))
|
|
2235
|
+
if (isChannelPartialDeliveryError(error)) visibleReplySent = true;
|
|
2284
2236
|
params.runtime.error?.(`feishu[${account.accountId}] ${info.kind} reply failed: ${String(error)}`);
|
|
2285
2237
|
await queueIdleSideEffects().catch((cleanupError) => params.runtime.error?.(`feishu[${account.accountId}] reply error cleanup failed: ${String(cleanupError)}`));
|
|
2286
2238
|
};
|
|
@@ -2290,7 +2242,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2290
2242
|
observeMessageSent: true,
|
|
2291
2243
|
onDelivered: (_payload, info, result) => {
|
|
2292
2244
|
if (result?.visibleReplySent) {
|
|
2293
|
-
|
|
2245
|
+
visibleReplySent = true;
|
|
2294
2246
|
if (info.kind === "final") replyOutcome = void 0;
|
|
2295
2247
|
return;
|
|
2296
2248
|
}
|
|
@@ -2367,7 +2319,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2367
2319
|
content: resolvedText,
|
|
2368
2320
|
kind: "card"
|
|
2369
2321
|
})), resolvedText);
|
|
2370
|
-
|
|
2322
|
+
visibleReplySent = true;
|
|
2371
2323
|
return mergeFeishuReplyDeliveryResults(deliveredResults, resolvedText);
|
|
2372
2324
|
}
|
|
2373
2325
|
if (shouldDeliverText) {
|
|
@@ -2470,11 +2422,7 @@ function createFeishuReplyDispatcher(params) {
|
|
|
2470
2422
|
onCompactionStart: previewStreamingEnabled ? () => updateStreamingStatusLine("📦 **Compacting context...**") : void 0,
|
|
2471
2423
|
onCompactionEnd: previewStreamingEnabled ? () => updateStreamingStatusLine("") : void 0
|
|
2472
2424
|
},
|
|
2473
|
-
ensureNoVisibleReplyFallback
|
|
2474
|
-
getVisibleReplyState: () => ({
|
|
2475
|
-
visibleReplySent,
|
|
2476
|
-
skippedFinalReason: replyOutcome?.kind === "skipped" || replyOutcome?.kind === "suppressed" ? replyOutcome.reason : null
|
|
2477
|
-
})
|
|
2425
|
+
ensureNoVisibleReplyFallback
|
|
2478
2426
|
};
|
|
2479
2427
|
}
|
|
2480
2428
|
//#endregion
|
|
@@ -2514,7 +2462,7 @@ async function resolveFeishuAudioTranscript(params) {
|
|
|
2514
2462
|
return;
|
|
2515
2463
|
}
|
|
2516
2464
|
}
|
|
2517
|
-
function parseFeishuMessageEvent(event, botOpenId,
|
|
2465
|
+
function parseFeishuMessageEvent(event, botOpenId, preparedContent) {
|
|
2518
2466
|
const mentionedBot = checkBotMentioned(event, botOpenId);
|
|
2519
2467
|
const hasAnyMention = (event.message.mentions?.length ?? 0) > 0;
|
|
2520
2468
|
const content = preparedContent ?? normalizeMentions(parseMessageContent(event.message.content, event.message.message_type), event.message.mentions, botOpenId);
|
|
@@ -2573,7 +2521,7 @@ async function filterFetchedGroupContextMessages(messages, params) {
|
|
|
2573
2521
|
}) ? message : void 0))).filter((message) => message !== void 0);
|
|
2574
2522
|
}
|
|
2575
2523
|
async function handleFeishuMessage(params) {
|
|
2576
|
-
const { event, preparedContent, botOpenId,
|
|
2524
|
+
const { event, preparedContent, botOpenId, runtime, channelRuntime, chatHistories, accountId, processingClaim, messageDedupeKey: messageDedupeKeyOverride, turnAdoptionLifecycle } = params;
|
|
2577
2525
|
let cfg = getFeishuRuntime().config.current();
|
|
2578
2526
|
let account = resolveFeishuRuntimeAccount({
|
|
2579
2527
|
cfg,
|
|
@@ -2593,7 +2541,7 @@ async function handleFeishuMessage(params) {
|
|
|
2593
2541
|
log(`feishu: skipping duplicate message ${messageId}`);
|
|
2594
2542
|
return;
|
|
2595
2543
|
}
|
|
2596
|
-
let ctx = parseFeishuMessageEvent(event, botOpenId,
|
|
2544
|
+
let ctx = parseFeishuMessageEvent(event, botOpenId, preparedContent);
|
|
2597
2545
|
const isGroup = isFeishuGroupChatType(ctx.chatType);
|
|
2598
2546
|
const isDirect = !isGroup;
|
|
2599
2547
|
const directPreDispatchTarget = isDirect ? getFeishuSyntheticDirectPreDispatchTarget(event) : void 0;
|
|
@@ -2643,7 +2591,7 @@ async function handleFeishuMessage(params) {
|
|
|
2643
2591
|
log(`feishu[${account.accountId}]: dropping bot message ${ctx.messageId} (local mention not verifiable)`);
|
|
2644
2592
|
return;
|
|
2645
2593
|
}
|
|
2646
|
-
const deliveredCtx = parseFeishuMessageEvent(verifiedEvent, localBotOpenId,
|
|
2594
|
+
const deliveredCtx = parseFeishuMessageEvent(verifiedEvent, localBotOpenId, preparedContent);
|
|
2647
2595
|
ctx = {
|
|
2648
2596
|
...deliveredCtx,
|
|
2649
2597
|
mentionedBot: true,
|
|
@@ -3457,13 +3405,13 @@ async function handleFeishuMessage(params) {
|
|
|
3457
3405
|
};
|
|
3458
3406
|
const strategy = cfg.broadcast?.strategy === "sequential" ? "sequential" : "parallel";
|
|
3459
3407
|
const activeAgentId = ctx.mentionedBot || !requireMention ? normalizeAgentId$1(route.agentId) : null;
|
|
3460
|
-
const agentIds = (cfg.agents?.
|
|
3408
|
+
const agentIds = Object.keys(cfg.agents?.entries ?? {}).map((id) => normalizeAgentId$1(id));
|
|
3461
3409
|
const hasKnownAgents = agentIds.length > 0;
|
|
3462
3410
|
log(`feishu[${account.accountId}]: broadcasting to ${broadcastAgents.length} agents (strategy=${strategy}, active=${activeAgentId ?? "none"})`);
|
|
3463
3411
|
const dispatchForAgent = async (agentId) => {
|
|
3464
3412
|
const normalizedAgentId = normalizeAgentId$1(agentId);
|
|
3465
3413
|
if (hasKnownAgents && !agentIds.includes(normalizedAgentId)) {
|
|
3466
|
-
log(`feishu[${account.accountId}]: broadcast agent ${agentId} not found in agents.
|
|
3414
|
+
log(`feishu[${account.accountId}]: broadcast agent ${agentId} not found in agents.entries; skipping`);
|
|
3467
3415
|
return;
|
|
3468
3416
|
}
|
|
3469
3417
|
let agentClaim;
|
|
@@ -3684,6 +3632,26 @@ const processedCardActions = /* @__PURE__ */ new Map();
|
|
|
3684
3632
|
const resolvedCardActionChatTypes = /* @__PURE__ */ new Map();
|
|
3685
3633
|
//#endregion
|
|
3686
3634
|
//#region extensions/feishu/src/card-ux-shared.ts
|
|
3635
|
+
function buildFeishuActionCard(params) {
|
|
3636
|
+
return {
|
|
3637
|
+
schema: "2.0",
|
|
3638
|
+
config: { width_mode: "fill" },
|
|
3639
|
+
header: {
|
|
3640
|
+
title: {
|
|
3641
|
+
tag: "plain_text",
|
|
3642
|
+
content: params.title
|
|
3643
|
+
},
|
|
3644
|
+
template: params.template
|
|
3645
|
+
},
|
|
3646
|
+
body: { elements: [{
|
|
3647
|
+
tag: "markdown",
|
|
3648
|
+
content: params.content
|
|
3649
|
+
}, {
|
|
3650
|
+
tag: "action",
|
|
3651
|
+
actions: params.actions
|
|
3652
|
+
}] }
|
|
3653
|
+
};
|
|
3654
|
+
}
|
|
3687
3655
|
function buildFeishuCardButton(params) {
|
|
3688
3656
|
return {
|
|
3689
3657
|
tag: "button",
|
|
@@ -3711,56 +3679,44 @@ const FEISHU_APPROVAL_CONFIRM_ACTION = "feishu.approval.confirm";
|
|
|
3711
3679
|
const FEISHU_APPROVAL_CANCEL_ACTION = "feishu.approval.cancel";
|
|
3712
3680
|
function createApprovalCard(params) {
|
|
3713
3681
|
const context = buildFeishuCardInteractionContext(params);
|
|
3714
|
-
return {
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
}, {
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
c: context
|
|
3737
|
-
})
|
|
3738
|
-
}), buildFeishuCardButton({
|
|
3739
|
-
label: params.cancelLabel ?? "Cancel",
|
|
3740
|
-
value: createFeishuCardInteractionEnvelope({
|
|
3741
|
-
k: "button",
|
|
3742
|
-
a: FEISHU_APPROVAL_CANCEL_ACTION,
|
|
3743
|
-
c: context
|
|
3744
|
-
})
|
|
3745
|
-
})]
|
|
3746
|
-
}] }
|
|
3747
|
-
};
|
|
3682
|
+
return buildFeishuActionCard({
|
|
3683
|
+
title: "Confirm action",
|
|
3684
|
+
template: "orange",
|
|
3685
|
+
content: params.prompt,
|
|
3686
|
+
actions: [buildFeishuCardButton({
|
|
3687
|
+
label: params.confirmLabel ?? "Confirm",
|
|
3688
|
+
type: "primary",
|
|
3689
|
+
value: createFeishuCardInteractionEnvelope({
|
|
3690
|
+
k: "quick",
|
|
3691
|
+
a: FEISHU_APPROVAL_CONFIRM_ACTION,
|
|
3692
|
+
q: params.command,
|
|
3693
|
+
c: context
|
|
3694
|
+
})
|
|
3695
|
+
}), buildFeishuCardButton({
|
|
3696
|
+
label: params.cancelLabel ?? "Cancel",
|
|
3697
|
+
value: createFeishuCardInteractionEnvelope({
|
|
3698
|
+
k: "button",
|
|
3699
|
+
a: FEISHU_APPROVAL_CANCEL_ACTION,
|
|
3700
|
+
c: context
|
|
3701
|
+
})
|
|
3702
|
+
})]
|
|
3703
|
+
});
|
|
3748
3704
|
}
|
|
3749
3705
|
//#endregion
|
|
3750
3706
|
//#region extensions/feishu/src/card-action.ts
|
|
3751
3707
|
const FEISHU_APPROVAL_CARD_TTL_MS = 3e5;
|
|
3752
3708
|
const FEISHU_CARD_ACTION_TOKEN_TTL_MS = 9e5;
|
|
3753
|
-
function
|
|
3709
|
+
function pruneExpiredCardEntries(cache, now) {
|
|
3754
3710
|
const validNow = asDateTimestampMs(now);
|
|
3755
3711
|
if (validNow === void 0) {
|
|
3756
|
-
|
|
3712
|
+
cache.clear();
|
|
3757
3713
|
return;
|
|
3758
3714
|
}
|
|
3759
|
-
for (const [key, entry] of
|
|
3715
|
+
for (const [key, entry] of cache) if (!isFutureDateTimestampMs(entry.expiresAt, { nowMs: validNow })) cache.delete(key);
|
|
3760
3716
|
}
|
|
3761
3717
|
function beginFeishuCardActionToken(params) {
|
|
3762
3718
|
const now = params.now ?? Date.now();
|
|
3763
|
-
|
|
3719
|
+
pruneExpiredCardEntries(processedCardActions, now);
|
|
3764
3720
|
const normalizedToken = params.token.trim();
|
|
3765
3721
|
if (!normalizedToken) return false;
|
|
3766
3722
|
const key = `${params.accountId}:${normalizedToken}`;
|
|
@@ -3838,28 +3794,15 @@ async function dispatchSyntheticCommand(params) {
|
|
|
3838
3794
|
accountId: params.accountId
|
|
3839
3795
|
});
|
|
3840
3796
|
}
|
|
3841
|
-
const resolvedChatTypeCache = resolvedCardActionChatTypes;
|
|
3842
3797
|
const CHAT_TYPE_CACHE_TTL_MS = 18e5;
|
|
3843
3798
|
const CHAT_TYPE_CACHE_MAX_SIZE = 5e3;
|
|
3844
|
-
function pruneChatTypeCache(now) {
|
|
3845
|
-
const validNow = asDateTimestampMs(now);
|
|
3846
|
-
if (validNow === void 0) {
|
|
3847
|
-
resolvedChatTypeCache.clear();
|
|
3848
|
-
return;
|
|
3849
|
-
}
|
|
3850
|
-
for (const [key, entry] of resolvedChatTypeCache.entries()) {
|
|
3851
|
-
const expiresAt = asDateTimestampMs(entry.expiresAt);
|
|
3852
|
-
if (expiresAt === void 0 || expiresAt <= validNow) resolvedChatTypeCache.delete(key);
|
|
3853
|
-
}
|
|
3854
|
-
pruneMapToMaxSize(resolvedChatTypeCache, CHAT_TYPE_CACHE_MAX_SIZE);
|
|
3855
|
-
}
|
|
3856
3799
|
function sanitizeLogValue(v) {
|
|
3857
3800
|
return truncateUtf16Safe(v.replace(/[\r\n]/g, " "), 500);
|
|
3858
3801
|
}
|
|
3859
3802
|
function cacheResolvedCardActionChatType(cacheKey, value, now) {
|
|
3860
3803
|
const expiresAt = resolveExpiresAtMsFromDurationMs(CHAT_TYPE_CACHE_TTL_MS, { nowMs: now });
|
|
3861
|
-
|
|
3862
|
-
if (expiresAt !== void 0)
|
|
3804
|
+
resolvedCardActionChatTypes.delete(cacheKey);
|
|
3805
|
+
if (expiresAt !== void 0) resolvedCardActionChatTypes.set(cacheKey, {
|
|
3863
3806
|
value,
|
|
3864
3807
|
expiresAt
|
|
3865
3808
|
});
|
|
@@ -3871,8 +3814,9 @@ async function resolveCardActionChatType(params) {
|
|
|
3871
3814
|
if (!chatId) return "p2p";
|
|
3872
3815
|
const cacheKey = `${params.account.accountId}:${chatId}`;
|
|
3873
3816
|
const now = Date.now();
|
|
3874
|
-
|
|
3875
|
-
|
|
3817
|
+
pruneExpiredCardEntries(resolvedCardActionChatTypes, now);
|
|
3818
|
+
pruneMapToMaxSize(resolvedCardActionChatTypes, CHAT_TYPE_CACHE_MAX_SIZE);
|
|
3819
|
+
const cached = resolvedCardActionChatTypes.get(cacheKey);
|
|
3876
3820
|
if (cached) return cached.value;
|
|
3877
3821
|
try {
|
|
3878
3822
|
const response = await createFeishuClient(params.account).im.chat.get({ path: { chat_id: chatId } });
|
|
@@ -3987,7 +3931,7 @@ async function handleFeishuCardAction(params) {
|
|
|
3987
3931
|
await sendInvalidInteractionNotice("malformed");
|
|
3988
3932
|
return;
|
|
3989
3933
|
}
|
|
3990
|
-
const content =
|
|
3934
|
+
const content = decoded.text;
|
|
3991
3935
|
log(`feishu[${account.accountId}]: handling card action from ${event.operator.open_id}: ${content}`);
|
|
3992
3936
|
await dispatchSyntheticCommand({
|
|
3993
3937
|
...params,
|
|
@@ -4223,7 +4167,6 @@ function createFeishuDurableIngress(options) {
|
|
|
4223
4167
|
const abandonHandlers = /* @__PURE__ */ new Set();
|
|
4224
4168
|
const wrappedLifecycle = {
|
|
4225
4169
|
...lifecycle,
|
|
4226
|
-
onAdopted: lifecycle.onAdopted,
|
|
4227
4170
|
onAbandoned: async () => {
|
|
4228
4171
|
await Promise.allSettled([...abandonHandlers].map(async (handler) => await handler()));
|
|
4229
4172
|
await lifecycle.onAbandoned();
|
|
@@ -4311,7 +4254,6 @@ function createFeishuDurableIngress(options) {
|
|
|
4311
4254
|
//#region extensions/feishu/src/monitor.state.ts
|
|
4312
4255
|
const wsClients = /* @__PURE__ */ new Map();
|
|
4313
4256
|
const botOpenIds = /* @__PURE__ */ new Map();
|
|
4314
|
-
const botNames = /* @__PURE__ */ new Map();
|
|
4315
4257
|
const botIdentityRevisions = /* @__PURE__ */ new Map();
|
|
4316
4258
|
const FEISHU_WEBHOOK_MAX_BODY_BYTES = 65536;
|
|
4317
4259
|
const FEISHU_WEBHOOK_BODY_TIMEOUT_MS = 5e3;
|
|
@@ -4323,15 +4265,12 @@ function readFeishuBotIdentityRevision(accountId) {
|
|
|
4323
4265
|
function bumpBotIdentityRevision(accountId) {
|
|
4324
4266
|
botIdentityRevisions.set(accountId, readFeishuBotIdentityRevision(accountId) + 1);
|
|
4325
4267
|
}
|
|
4326
|
-
function setFeishuBotIdentityState(accountId,
|
|
4327
|
-
botOpenIds.set(accountId,
|
|
4328
|
-
if (identity.botName) botNames.set(accountId, identity.botName);
|
|
4329
|
-
else botNames.delete(accountId);
|
|
4268
|
+
function setFeishuBotIdentityState(accountId, botOpenId) {
|
|
4269
|
+
botOpenIds.set(accountId, botOpenId);
|
|
4330
4270
|
bumpBotIdentityRevision(accountId);
|
|
4331
4271
|
}
|
|
4332
4272
|
function clearFeishuBotIdentityState(accountId) {
|
|
4333
4273
|
botOpenIds.delete(accountId);
|
|
4334
|
-
botNames.delete(accountId);
|
|
4335
4274
|
bumpBotIdentityRevision(accountId);
|
|
4336
4275
|
}
|
|
4337
4276
|
function recordWebhookStatus(runtime, accountId, path, statusCode) {
|
|
@@ -4354,16 +4293,8 @@ const BOT_IDENTITY_RETRY_DELAYS_MS = [
|
|
|
4354
4293
|
];
|
|
4355
4294
|
function applyBotIdentityState(accountId, identity) {
|
|
4356
4295
|
const botOpenId = normalizeOptionalString(identity.botOpenId);
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
botOpenId: botOpenId ?? "",
|
|
4360
|
-
botName
|
|
4361
|
-
});
|
|
4362
|
-
return {
|
|
4363
|
-
botOpenId,
|
|
4364
|
-
botName,
|
|
4365
|
-
source: botOpenId ? identity.source : void 0
|
|
4366
|
-
};
|
|
4296
|
+
setFeishuBotIdentityState(accountId, botOpenId ?? "");
|
|
4297
|
+
return botOpenId;
|
|
4367
4298
|
}
|
|
4368
4299
|
async function retryBotIdentityProbe(account, accountId, runtime, abortSignal) {
|
|
4369
4300
|
const log = runtime?.log ?? console.log;
|
|
@@ -4377,7 +4308,7 @@ async function retryBotIdentityProbe(account, accountId, runtime, abortSignal) {
|
|
|
4377
4308
|
allowCachedFallback: false
|
|
4378
4309
|
});
|
|
4379
4310
|
if (normalizeOptionalString(identity.botOpenId) && identity.source === "provider") {
|
|
4380
|
-
log(`feishu[${accountId}]: bot open_id recovered via background retry: ${applyBotIdentityState(accountId, identity)
|
|
4311
|
+
log(`feishu[${accountId}]: bot open_id recovered via background retry: ${applyBotIdentityState(accountId, identity)}`);
|
|
4381
4312
|
return;
|
|
4382
4313
|
}
|
|
4383
4314
|
const nextDelay = BOT_IDENTITY_RETRY_DELAYS_MS[i + 1];
|
|
@@ -4402,68 +4333,53 @@ const QUICK_ACTION_MENU_KEYS = /* @__PURE__ */ new Set([
|
|
|
4402
4333
|
"quick_actions",
|
|
4403
4334
|
"launcher"
|
|
4404
4335
|
]);
|
|
4405
|
-
function isFeishuQuickActionMenuEventKey(eventKey) {
|
|
4406
|
-
return QUICK_ACTION_MENU_KEYS.has(normalizeOptionalLowercaseString(eventKey) ?? "");
|
|
4407
|
-
}
|
|
4408
4336
|
function createQuickActionLauncherCard(params) {
|
|
4409
4337
|
const context = buildFeishuCardInteractionContext(params);
|
|
4410
|
-
return {
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
content: "Run common actions without typing raw commands."
|
|
4423
|
-
}, {
|
|
4424
|
-
tag: "action",
|
|
4425
|
-
actions: [
|
|
4426
|
-
buildFeishuCardButton({
|
|
4427
|
-
label: "Help",
|
|
4428
|
-
value: createFeishuCardInteractionEnvelope({
|
|
4429
|
-
k: "quick",
|
|
4430
|
-
a: "feishu.quick_actions.help",
|
|
4431
|
-
q: "/help",
|
|
4432
|
-
c: context
|
|
4433
|
-
})
|
|
4434
|
-
}),
|
|
4435
|
-
buildFeishuCardButton({
|
|
4436
|
-
label: "New session",
|
|
4437
|
-
type: "primary",
|
|
4438
|
-
value: createFeishuCardInteractionEnvelope({
|
|
4439
|
-
k: "meta",
|
|
4440
|
-
a: FEISHU_APPROVAL_REQUEST_ACTION,
|
|
4441
|
-
m: {
|
|
4442
|
-
command: "/new",
|
|
4443
|
-
prompt: "Start a fresh session? This will reset the current chat context."
|
|
4444
|
-
},
|
|
4445
|
-
c: context
|
|
4446
|
-
})
|
|
4447
|
-
}),
|
|
4448
|
-
buildFeishuCardButton({
|
|
4449
|
-
label: "Reset",
|
|
4450
|
-
type: "danger",
|
|
4451
|
-
value: createFeishuCardInteractionEnvelope({
|
|
4452
|
-
k: "meta",
|
|
4453
|
-
a: FEISHU_APPROVAL_REQUEST_ACTION,
|
|
4454
|
-
m: {
|
|
4455
|
-
command: "/reset",
|
|
4456
|
-
prompt: "Reset this session now? Any active conversation state will be cleared."
|
|
4457
|
-
},
|
|
4458
|
-
c: context
|
|
4459
|
-
})
|
|
4338
|
+
return buildFeishuActionCard({
|
|
4339
|
+
title: "Quick actions",
|
|
4340
|
+
template: "indigo",
|
|
4341
|
+
content: "Run common actions without typing raw commands.",
|
|
4342
|
+
actions: [
|
|
4343
|
+
buildFeishuCardButton({
|
|
4344
|
+
label: "Help",
|
|
4345
|
+
value: createFeishuCardInteractionEnvelope({
|
|
4346
|
+
k: "quick",
|
|
4347
|
+
a: "feishu.quick_actions.help",
|
|
4348
|
+
q: "/help",
|
|
4349
|
+
c: context
|
|
4460
4350
|
})
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4351
|
+
}),
|
|
4352
|
+
buildFeishuCardButton({
|
|
4353
|
+
label: "New session",
|
|
4354
|
+
type: "primary",
|
|
4355
|
+
value: createFeishuCardInteractionEnvelope({
|
|
4356
|
+
k: "meta",
|
|
4357
|
+
a: FEISHU_APPROVAL_REQUEST_ACTION,
|
|
4358
|
+
m: {
|
|
4359
|
+
command: "/new",
|
|
4360
|
+
prompt: "Start a fresh session? This will reset the current chat context."
|
|
4361
|
+
},
|
|
4362
|
+
c: context
|
|
4363
|
+
})
|
|
4364
|
+
}),
|
|
4365
|
+
buildFeishuCardButton({
|
|
4366
|
+
label: "Reset",
|
|
4367
|
+
type: "danger",
|
|
4368
|
+
value: createFeishuCardInteractionEnvelope({
|
|
4369
|
+
k: "meta",
|
|
4370
|
+
a: FEISHU_APPROVAL_REQUEST_ACTION,
|
|
4371
|
+
m: {
|
|
4372
|
+
command: "/reset",
|
|
4373
|
+
prompt: "Reset this session now? Any active conversation state will be cleared."
|
|
4374
|
+
},
|
|
4375
|
+
c: context
|
|
4376
|
+
})
|
|
4377
|
+
})
|
|
4378
|
+
]
|
|
4379
|
+
});
|
|
4464
4380
|
}
|
|
4465
4381
|
async function maybeHandleFeishuQuickActionMenu(params) {
|
|
4466
|
-
if (!
|
|
4382
|
+
if (!QUICK_ACTION_MENU_KEYS.has(normalizeOptionalLowercaseString(params.eventKey) ?? "")) return false;
|
|
4467
4383
|
const now = asDateTimestampMs(params.now ?? Date.now());
|
|
4468
4384
|
const expiresAt = now === void 0 ? void 0 : resolveExpiresAtMsFromDurationMs(FEISHU_QUICK_ACTION_CARD_TTL_MS, { nowMs: now });
|
|
4469
4385
|
if (expiresAt === void 0) {
|
|
@@ -4526,7 +4442,6 @@ function createFeishuBotMenuHandler(params) {
|
|
|
4526
4442
|
const log = runtime?.log ?? console.log;
|
|
4527
4443
|
const error = runtime?.error ?? console.error;
|
|
4528
4444
|
const getBotOpenId = params.getBotOpenId ?? ((id) => botOpenIds.get(id));
|
|
4529
|
-
const getBotName = params.getBotName ?? ((id) => botNames.get(id));
|
|
4530
4445
|
const isActive = params.isAccountActive ?? (() => true);
|
|
4531
4446
|
const handle = async (data) => {
|
|
4532
4447
|
try {
|
|
@@ -4577,7 +4492,6 @@ function createFeishuBotMenuHandler(params) {
|
|
|
4577
4492
|
cfg,
|
|
4578
4493
|
event: syntheticEvent,
|
|
4579
4494
|
botOpenId: getBotOpenId(accountId),
|
|
4580
|
-
botName: getBotName(accountId),
|
|
4581
4495
|
runtime,
|
|
4582
4496
|
channelRuntime: params.channelRuntime,
|
|
4583
4497
|
chatHistories,
|
|
@@ -5172,7 +5086,7 @@ async function resolveDriveCommentEventTurn(params) {
|
|
|
5172
5086
|
return null;
|
|
5173
5087
|
}
|
|
5174
5088
|
const context = await fetchDriveCommentContext({
|
|
5175
|
-
client: createClient ? createClient(account ?? { accountId }) : createFeishuClient((await import("./
|
|
5089
|
+
client: createClient ? createClient(account ?? { accountId }) : createFeishuClient((await import("./doctor-contract-B1B9ogdd.mjs").then((n) => n.c)).resolveFeishuAccount({
|
|
5176
5090
|
cfg,
|
|
5177
5091
|
accountId
|
|
5178
5092
|
})),
|
|
@@ -5516,20 +5430,11 @@ function createSequentialQueue(options = {}) {
|
|
|
5516
5430
|
async function boundedRun(key, task, timeoutMs, onTaskTimeout) {
|
|
5517
5431
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return task();
|
|
5518
5432
|
const resolvedTimeoutMs = resolveTimerTimeoutMs(timeoutMs, DEFAULT_TASK_TIMEOUT_MS);
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
onTaskTimeout?.(key, resolvedTimeoutMs);
|
|
5524
|
-
} catch {}
|
|
5525
|
-
resolve();
|
|
5526
|
-
}, resolvedTimeoutMs);
|
|
5433
|
+
await raceWithTimeout(task, resolvedTimeoutMs, () => {
|
|
5434
|
+
try {
|
|
5435
|
+
onTaskTimeout?.(key, resolvedTimeoutMs);
|
|
5436
|
+
} catch {}
|
|
5527
5437
|
});
|
|
5528
|
-
try {
|
|
5529
|
-
await Promise.race([task(), timeoutPromise]);
|
|
5530
|
-
} finally {
|
|
5531
|
-
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
5532
|
-
}
|
|
5533
5438
|
}
|
|
5534
5439
|
//#endregion
|
|
5535
5440
|
//#region extensions/feishu/src/monitor.comment-notice-handler.ts
|
|
@@ -5638,7 +5543,7 @@ function resolveFeishuDebounceMentions(params) {
|
|
|
5638
5543
|
const botMentions = merged.filter((mention) => mention.id.open_id?.trim() === normalizedBotOpenId);
|
|
5639
5544
|
return botMentions.length > 0 ? botMentions : void 0;
|
|
5640
5545
|
}
|
|
5641
|
-
function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, runtime, chatHistories, fireAndForget, isAccountActive = () => true, trackTask, handleMessage, resolveDebounceText: resolveText, hasProcessedMessage, getBotOpenId = () => void 0,
|
|
5546
|
+
function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, runtime, chatHistories, fireAndForget, isAccountActive = () => true, trackTask, handleMessage, resolveDebounceText: resolveText, hasProcessedMessage, getBotOpenId = () => void 0, resolveSequentialKey = ({ accountId: accountIdLocal, event }) => `feishu:${accountIdLocal}:${event.message.chat_id?.trim() || "unknown"}`, statusSink, resolveIngressLifecycle }) {
|
|
5642
5547
|
const readConfig = createRuntimeConfigReader(cfg);
|
|
5643
5548
|
const resolveDebounceMs = () => channelRuntime.debounce.resolveInboundDebounceMs({
|
|
5644
5549
|
cfg: readConfig(),
|
|
@@ -5654,8 +5559,7 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5654
5559
|
accountId,
|
|
5655
5560
|
event,
|
|
5656
5561
|
preparedContent,
|
|
5657
|
-
botOpenId: getBotOpenId(accountId)
|
|
5658
|
-
botName: getBotName(accountId)
|
|
5562
|
+
botOpenId: getBotOpenId(accountId)
|
|
5659
5563
|
});
|
|
5660
5564
|
const task = async () => {
|
|
5661
5565
|
if (turnAdoptionLifecycle?.abortSignal.aborted) {
|
|
@@ -5668,7 +5572,6 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5668
5572
|
event,
|
|
5669
5573
|
preparedContent,
|
|
5670
5574
|
botOpenId: getBotOpenId(accountId),
|
|
5671
|
-
botName: getBotName(accountId),
|
|
5672
5575
|
runtime,
|
|
5673
5576
|
channelRuntime,
|
|
5674
5577
|
chatHistories,
|
|
@@ -5682,14 +5585,10 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5682
5585
|
};
|
|
5683
5586
|
await enqueue(sequentialKey, task);
|
|
5684
5587
|
};
|
|
5685
|
-
const resolveSenderDebounceId = (event) => {
|
|
5686
|
-
return event.sender.sender_id.open_id?.trim() || event.sender.sender_id.user_id?.trim() || void 0;
|
|
5687
|
-
};
|
|
5688
5588
|
const resolveDebounceText = (event) => {
|
|
5689
5589
|
return resolveText({
|
|
5690
5590
|
event,
|
|
5691
|
-
botOpenId: getBotOpenId(accountId)
|
|
5692
|
-
botName: getBotName(accountId)
|
|
5591
|
+
botOpenId: getBotOpenId(accountId)
|
|
5693
5592
|
}).trim();
|
|
5694
5593
|
};
|
|
5695
5594
|
const recordSuppressedMessageIds = async (entries, dispatchDedupeKey) => {
|
|
@@ -5708,7 +5607,7 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5708
5607
|
resolveDebounceMs,
|
|
5709
5608
|
buildKey: ({ event }) => {
|
|
5710
5609
|
const chatId = event.message.chat_id?.trim();
|
|
5711
|
-
const senderId =
|
|
5610
|
+
const senderId = event.sender.sender_id.open_id?.trim() || event.sender.sender_id.user_id?.trim();
|
|
5712
5611
|
if (!chatId || !senderId) return null;
|
|
5713
5612
|
const threadId = event.message.root_id?.trim() || event.message.thread_id?.trim();
|
|
5714
5613
|
return `feishu:${accountId}:${chatId}:${threadId ? `thread:${threadId}` : "chat"}:${senderId}`;
|
|
@@ -5813,7 +5712,7 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5813
5712
|
return;
|
|
5814
5713
|
}
|
|
5815
5714
|
const messageDedupeKey = resolveFeishuMessageDedupeKey(event);
|
|
5816
|
-
if (event.message.message_type.trim() === "post" && messageDedupeKey !== messageId && await hasProcessedMessage(messageId, accountId, log) && parsePostContent(event.message.content).attachments.length === 0) {
|
|
5715
|
+
if (event.message.message_type.trim() === "post" && messageDedupeKey !== messageId && await hasProcessedMessage(messageId, accountId, log) && parsePostContent(event.message.content, { includeTopLevelFiles: false }).attachments.length === 0) {
|
|
5817
5716
|
log(`feishu[${accountId}]: dropping duplicate event for message ${messageId}`);
|
|
5818
5717
|
await completeSuppressedIngress();
|
|
5819
5718
|
return;
|
|
@@ -5847,11 +5746,8 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5847
5746
|
debounceEntry.abandoned = true;
|
|
5848
5747
|
claim.handle.release({ error: /* @__PURE__ */ new Error("feishu-ingress-abandoned-before-flush") });
|
|
5849
5748
|
});
|
|
5850
|
-
const processMessage = async () => {
|
|
5851
|
-
await inboundDebouncer.enqueue(debounceEntry);
|
|
5852
|
-
};
|
|
5853
5749
|
if (turnAdoptionLifecycle) try {
|
|
5854
|
-
await
|
|
5750
|
+
await inboundDebouncer.enqueue(debounceEntry);
|
|
5855
5751
|
return { kind: "deferred" };
|
|
5856
5752
|
} catch (err) {
|
|
5857
5753
|
if (claim.kind === "claimed") claim.handle.release({ error: err });
|
|
@@ -5860,7 +5756,7 @@ function createFeishuMessageReceiveHandler({ cfg, channelRuntime, accountId, run
|
|
|
5860
5756
|
error: err
|
|
5861
5757
|
};
|
|
5862
5758
|
}
|
|
5863
|
-
const processing =
|
|
5759
|
+
const processing = inboundDebouncer.enqueue(debounceEntry).catch((err) => {
|
|
5864
5760
|
if (claim.kind === "claimed") claim.handle.release({ error: err });
|
|
5865
5761
|
error(`feishu[${accountId}]: error handling message: ${String(err)}`);
|
|
5866
5762
|
});
|
|
@@ -5878,54 +5774,6 @@ function buildFeishuWebhookRateLimitKey(params) {
|
|
|
5878
5774
|
return `${params.accountId === void 0 ? params.path : `${params.accountId}:${params.path}`}:${normalizeFeishuWebhookRateLimitClient(params.clientIp)}`;
|
|
5879
5775
|
}
|
|
5880
5776
|
//#endregion
|
|
5881
|
-
//#region extensions/feishu/src/monitor.webhook-legacy.ts
|
|
5882
|
-
const feishuWebhookHost = webhookIngressSdk;
|
|
5883
|
-
async function startFeishuLegacyWebhookListener(params) {
|
|
5884
|
-
const server = createServer((req, res) => {
|
|
5885
|
-
params.handleRequest(req, res).catch((error) => {
|
|
5886
|
-
params.onRequestError(error);
|
|
5887
|
-
if (!res.headersSent) res.statusCode = 500;
|
|
5888
|
-
res.end();
|
|
5889
|
-
});
|
|
5890
|
-
});
|
|
5891
|
-
let closing;
|
|
5892
|
-
const stopAccepting = () => {
|
|
5893
|
-
closing ??= new Promise((resolve, reject) => {
|
|
5894
|
-
server.close((error) => {
|
|
5895
|
-
if (error && extractErrorCode(error) !== "ERR_SERVER_NOT_RUNNING") reject(error);
|
|
5896
|
-
else resolve();
|
|
5897
|
-
});
|
|
5898
|
-
});
|
|
5899
|
-
closing.catch(() => {});
|
|
5900
|
-
};
|
|
5901
|
-
const close = async () => {
|
|
5902
|
-
stopAccepting();
|
|
5903
|
-
server.closeAllConnections();
|
|
5904
|
-
try {
|
|
5905
|
-
await closing;
|
|
5906
|
-
} finally {
|
|
5907
|
-
server.off("error", params.onFailure);
|
|
5908
|
-
}
|
|
5909
|
-
};
|
|
5910
|
-
server.on("error", params.onFailure);
|
|
5911
|
-
try {
|
|
5912
|
-
await new Promise((resolve, reject) => {
|
|
5913
|
-
server.once("error", reject);
|
|
5914
|
-
server.listen(params.endpoint.port, params.endpoint.host, () => {
|
|
5915
|
-
server.off("error", reject);
|
|
5916
|
-
resolve();
|
|
5917
|
-
});
|
|
5918
|
-
});
|
|
5919
|
-
} catch (error) {
|
|
5920
|
-
await close();
|
|
5921
|
-
throw error;
|
|
5922
|
-
}
|
|
5923
|
-
return {
|
|
5924
|
-
stopAccepting,
|
|
5925
|
-
close
|
|
5926
|
-
};
|
|
5927
|
-
}
|
|
5928
|
-
//#endregion
|
|
5929
5777
|
//#region extensions/feishu/src/monitor.transport.ts
|
|
5930
5778
|
const FEISHU_WEBHOOK_ACCEPTED_HEADER = "x-openclaw-delivery-accepted";
|
|
5931
5779
|
const FEISHU_WEBHOOK_ACCEPTED_VALUE = "durable";
|
|
@@ -6006,25 +5854,6 @@ function cleanupFeishuWsClient(params) {
|
|
|
6006
5854
|
wsClients.delete(accountId);
|
|
6007
5855
|
if (clearIdentity) clearFeishuBotIdentityState(accountId);
|
|
6008
5856
|
}
|
|
6009
|
-
function waitForFeishuWsCycleEnd(params) {
|
|
6010
|
-
if (params.abortSignal?.aborted) return Promise.resolve("abort");
|
|
6011
|
-
return new Promise((resolve) => {
|
|
6012
|
-
let settled = false;
|
|
6013
|
-
const finish = (result) => {
|
|
6014
|
-
if (settled) return;
|
|
6015
|
-
settled = true;
|
|
6016
|
-
if (handleAbort) params.abortSignal?.removeEventListener("abort", handleAbort);
|
|
6017
|
-
resolve(result);
|
|
6018
|
-
};
|
|
6019
|
-
const handleAbort = () => finish("abort");
|
|
6020
|
-
params.abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
6021
|
-
if (params.abortSignal?.aborted) {
|
|
6022
|
-
finish("abort");
|
|
6023
|
-
return;
|
|
6024
|
-
}
|
|
6025
|
-
params.terminalError.then(finish);
|
|
6026
|
-
});
|
|
6027
|
-
}
|
|
6028
5857
|
async function monitorWebSocket({ account, accountId, runtime, abortSignal, eventDispatcher, setSocketTerminator, statusSink }) {
|
|
6029
5858
|
const log = runtime?.log ?? console.log;
|
|
6030
5859
|
const error = runtime?.error ?? console.error;
|
|
@@ -6033,10 +5862,7 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
6033
5862
|
if (abortSignal?.aborted) break;
|
|
6034
5863
|
let wsClient;
|
|
6035
5864
|
try {
|
|
6036
|
-
|
|
6037
|
-
const terminalError = new Promise((resolve) => {
|
|
6038
|
-
reportTerminalError = resolve;
|
|
6039
|
-
});
|
|
5865
|
+
const { promise: terminalError, resolve: reportTerminalError } = createDeferred();
|
|
6040
5866
|
const handleWsError = (err) => {
|
|
6041
5867
|
if (isFeishuWsTerminalError(err)) {
|
|
6042
5868
|
reportTerminalError(err);
|
|
@@ -6079,11 +5905,8 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
6079
5905
|
await wsClient.start({ eventDispatcher });
|
|
6080
5906
|
attempt = 0;
|
|
6081
5907
|
log(`feishu[${accountId}]: WebSocket client started`);
|
|
6082
|
-
const cycleEnd = await
|
|
6083
|
-
|
|
6084
|
-
terminalError
|
|
6085
|
-
});
|
|
6086
|
-
if (cycleEnd === "abort") {
|
|
5908
|
+
const cycleEnd = await raceWithTimeoutAndAbort(terminalError, { abortSignal });
|
|
5909
|
+
if (cycleEnd.status !== "resolved") {
|
|
6087
5910
|
log(`feishu[${accountId}]: abort signal received, stopping`);
|
|
6088
5911
|
cleanupFeishuWsClient({
|
|
6089
5912
|
accountId,
|
|
@@ -6103,13 +5926,13 @@ async function monitorWebSocket({ account, accountId, runtime, abortSignal, even
|
|
|
6103
5926
|
setSocketTerminator?.(void 0);
|
|
6104
5927
|
if (abortSignal?.aborted) break;
|
|
6105
5928
|
const disconnectedAt = Date.now();
|
|
6106
|
-
statusSink?.(channelBlockedPatch(formatFeishuWsErrorForLog(cycleEnd), {
|
|
5929
|
+
statusSink?.(channelBlockedPatch(formatFeishuWsErrorForLog(cycleEnd.value), {
|
|
6107
5930
|
connected: false,
|
|
6108
5931
|
lastEventAt: disconnectedAt
|
|
6109
5932
|
}));
|
|
6110
5933
|
attempt += 1;
|
|
6111
5934
|
const delayMs = getFeishuWsReconnectDelayMs(attempt);
|
|
6112
|
-
error(`feishu[${accountId}]: WebSocket connection ended, recreating client in ${delayMs}ms: ${formatFeishuWsErrorForLog(cycleEnd)}`);
|
|
5935
|
+
error(`feishu[${accountId}]: WebSocket connection ended, recreating client in ${delayMs}ms: ${formatFeishuWsErrorForLog(cycleEnd.value)}`);
|
|
6113
5936
|
if (!await waitForAbortableDelay(delayMs, abortSignal)) break;
|
|
6114
5937
|
} catch (err) {
|
|
6115
5938
|
cleanupFeishuWsClient({
|
|
@@ -6147,7 +5970,8 @@ const webhookTargetsStore = createPluginRuntimeStore({
|
|
|
6147
5970
|
key: "feishu:webhook-targets",
|
|
6148
5971
|
errorMessage: "Feishu webhook routes are not registered"
|
|
6149
5972
|
});
|
|
6150
|
-
async function handleFeishuWebhook(req, res, webhookTargets
|
|
5973
|
+
async function handleFeishuWebhook(req, res, webhookTargets) {
|
|
5974
|
+
const legacyListener = getWebhookLegacyListener(req);
|
|
6151
5975
|
const requestUrl = req.url ?? "/";
|
|
6152
5976
|
const requestPath = requestUrl.split("?", 1)[0];
|
|
6153
5977
|
const targets = (webhookTargets.get(canonicalizeWebhookRouteKey(requestPath ?? "/")) ?? []).filter((target) => (!legacyListener || target.legacyListener?.port === legacyListener.port && target.legacyListener.host === legacyListener.host) && (target.rawPath.includes("?") ? requestUrl : requestPath) === target.rawPath);
|
|
@@ -6274,7 +6098,6 @@ async function monitorWebhook(params) {
|
|
|
6274
6098
|
const stopped = new AbortController();
|
|
6275
6099
|
const abortSignal = params.abortSignal ? AbortSignal.any([params.abortSignal, stopped.signal]) : stopped.signal;
|
|
6276
6100
|
const legacyListener = resolveFeishuLegacyWebhookListener(account.config);
|
|
6277
|
-
const gatewayOwnsLegacyListeners = feishuWebhookHost.getWebhookLegacyListener !== void 0;
|
|
6278
6101
|
const encryptKey = account.encryptKey?.trim();
|
|
6279
6102
|
if (!encryptKey) throw new Error(`Feishu account "${accountId}" webhook mode requires encryptKey`);
|
|
6280
6103
|
const rawPath = account.config.webhookPath ?? "/feishu/events";
|
|
@@ -6299,15 +6122,12 @@ async function monitorWebhook(params) {
|
|
|
6299
6122
|
pendingResponses: /* @__PURE__ */ new Map()
|
|
6300
6123
|
});
|
|
6301
6124
|
let unregisterRoute;
|
|
6302
|
-
let ownedListener;
|
|
6303
|
-
let listenerError;
|
|
6304
6125
|
let cleanupStarted = false;
|
|
6305
6126
|
let pendingDrain;
|
|
6306
6127
|
const cleanup = () => {
|
|
6307
6128
|
if (cleanupStarted) return pendingDrain;
|
|
6308
6129
|
cleanupStarted = true;
|
|
6309
6130
|
stopped.abort();
|
|
6310
|
-
ownedListener?.stopAccepting();
|
|
6311
6131
|
const identityRevision = readFeishuBotIdentityRevision(accountId);
|
|
6312
6132
|
pendingDrain = (async () => {
|
|
6313
6133
|
const pendingResponses = registration.target.pendingResponses;
|
|
@@ -6315,12 +6135,8 @@ async function monitorWebhook(params) {
|
|
|
6315
6135
|
if ((await raceWithTimeoutAndAbort(Promise.all(pendingResponses.values()), { timeoutMs: FEISHU_WEBHOOK_CLOSE_TIMEOUT_MS })).status === "timeout") for (const response of pendingResponses.keys()) response.destroy();
|
|
6316
6136
|
}
|
|
6317
6137
|
if (readFeishuBotIdentityRevision(accountId) === identityRevision && ![...webhookTargets.values()].some((targets) => targets.some((target) => target !== registration.target && target.accountId === accountId && !target.abortSignal?.aborted))) clearFeishuBotIdentityState(accountId);
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
unregisterRoute?.();
|
|
6321
|
-
} finally {
|
|
6322
|
-
await ownedListener?.close();
|
|
6323
|
-
}
|
|
6138
|
+
registration.unregister();
|
|
6139
|
+
unregisterRoute?.();
|
|
6324
6140
|
})();
|
|
6325
6141
|
return pendingDrain;
|
|
6326
6142
|
};
|
|
@@ -6338,33 +6154,17 @@ async function monitorWebhook(params) {
|
|
|
6338
6154
|
handler: (req, res) => handleFeishuWebhook(req, res, webhookTargets),
|
|
6339
6155
|
reuseExistingSameOwner: true,
|
|
6340
6156
|
throwOnFailure: true,
|
|
6341
|
-
legacyListener
|
|
6157
|
+
legacyListener,
|
|
6342
6158
|
log: runtime?.log
|
|
6343
6159
|
});
|
|
6344
|
-
if (
|
|
6345
|
-
const accountTargets = /* @__PURE__ */ new Map([[path, [registration.target]]]);
|
|
6346
|
-
ownedListener = await startFeishuLegacyWebhookListener({
|
|
6347
|
-
endpoint: legacyListener,
|
|
6348
|
-
handleRequest: (req, res) => handleFeishuWebhook(req, res, accountTargets, legacyListener),
|
|
6349
|
-
onFailure: (error) => {
|
|
6350
|
-
listenerError = error;
|
|
6351
|
-
stopped.abort(error);
|
|
6352
|
-
},
|
|
6353
|
-
onRequestError: (error) => (runtime?.error ?? console.error)(`feishu[${accountId}]: legacy webhook request failed: ${formatFeishuWsErrorForLog(error)}`)
|
|
6354
|
-
});
|
|
6355
|
-
}
|
|
6356
|
-
if (abortSignal.aborted) {
|
|
6357
|
-
if (listenerError) throw listenerError;
|
|
6358
|
-
return;
|
|
6359
|
-
}
|
|
6160
|
+
if (abortSignal.aborted) return;
|
|
6360
6161
|
const connectedAt = Date.now();
|
|
6361
6162
|
statusSink?.(channelReadyPatch({
|
|
6362
6163
|
lastConnectedAt: connectedAt,
|
|
6363
6164
|
lastEventAt: connectedAt
|
|
6364
6165
|
}));
|
|
6365
|
-
runtime?.log?.(
|
|
6166
|
+
runtime?.log?.(pathConflict ? `feishu[${accountId}]: ${pathConflict} The legacy listener keeps the old path working; move the path and callback before removing the legacyWebhook pin.` : `feishu[${accountId}]: webhook registered on Gateway port ${params.gatewayPort ?? 18789} at ${rawPath}; point the Feishu callback URL or reverse-proxy upstream to this Gateway route. ${legacyListener ? `The legacy listener on ${legacyListener.host}:${legacyListener.port} forwards here; remove the legacyWebhook pin after verifying delivery through the Gateway, or use legacyWebhook:false to override an inherited endpoint.` : "No legacy listener is configured."}`);
|
|
6366
6167
|
await waitUntilAbort(abortSignal, cleanup);
|
|
6367
|
-
if (listenerError) throw listenerError;
|
|
6368
6168
|
} finally {
|
|
6369
6169
|
await cleanup();
|
|
6370
6170
|
}
|
|
@@ -6552,9 +6352,9 @@ function createFeishuVcMeetingInvitedHandler(params) {
|
|
|
6552
6352
|
//#endregion
|
|
6553
6353
|
//#region extensions/feishu/src/sequential-key.ts
|
|
6554
6354
|
function getFeishuSequentialKey(params) {
|
|
6555
|
-
const { accountId, event, botOpenId,
|
|
6355
|
+
const { accountId, event, botOpenId, preparedContent } = params;
|
|
6556
6356
|
const baseKey = `feishu:${accountId}:${event.message.chat_id?.trim() || "unknown"}`;
|
|
6557
|
-
const text = (preparedContent ?? parseFeishuMessageEvent(event, botOpenId
|
|
6357
|
+
const text = (preparedContent ?? parseFeishuMessageEvent(event, botOpenId).content).trim();
|
|
6558
6358
|
if (isAbortRequestText(text)) return `${baseKey}:control`;
|
|
6559
6359
|
if (isBtwRequestText(text)) return `${baseKey}:btw`;
|
|
6560
6360
|
return baseKey;
|
|
@@ -6570,7 +6370,7 @@ async function resolveReactionSyntheticEvent(params) {
|
|
|
6570
6370
|
const senderUserId = event.user_id?.user_id?.trim();
|
|
6571
6371
|
const senderId = senderOpenId || senderUserId;
|
|
6572
6372
|
if (!emoji || !messageId || !senderId) return null;
|
|
6573
|
-
const { resolveFeishuAccount } = await import("./
|
|
6373
|
+
const { resolveFeishuAccount } = await import("./doctor-contract-B1B9ogdd.mjs").then((n) => n.c);
|
|
6574
6374
|
const reactionNotifications = resolveFeishuAccount({
|
|
6575
6375
|
cfg,
|
|
6576
6376
|
accountId
|
|
@@ -6703,7 +6503,6 @@ function registerEventHandlers(eventDispatcher, context) {
|
|
|
6703
6503
|
cfg,
|
|
6704
6504
|
event: syntheticEvent,
|
|
6705
6505
|
botOpenId: myBotId,
|
|
6706
|
-
botName: botNames.get(accountId),
|
|
6707
6506
|
runtime,
|
|
6708
6507
|
channelRuntime,
|
|
6709
6508
|
chatHistories,
|
|
@@ -6722,10 +6521,9 @@ function registerEventHandlers(eventDispatcher, context) {
|
|
|
6722
6521
|
isAccountActive: context.isAccountActive,
|
|
6723
6522
|
trackTask: context.trackTask,
|
|
6724
6523
|
handleMessage: handleFeishuMessage,
|
|
6725
|
-
resolveDebounceText: ({ event, botOpenId
|
|
6524
|
+
resolveDebounceText: ({ event, botOpenId }) => parseFeishuMessageEvent(event, botOpenId).content,
|
|
6726
6525
|
hasProcessedMessage: hasProcessedFeishuMessage,
|
|
6727
6526
|
getBotOpenId: (id) => botOpenIds.get(id),
|
|
6728
|
-
getBotName: (id) => botNames.get(id),
|
|
6729
6527
|
resolveSequentialKey: getFeishuSequentialKey,
|
|
6730
6528
|
resolveIngressLifecycle: context.resolveIngressLifecycle,
|
|
6731
6529
|
...context.statusSink ? { statusSink: context.statusSink } : {}
|
|
@@ -6811,13 +6609,12 @@ async function monitorSingleAccount(params) {
|
|
|
6811
6609
|
const botOpenIdSource = params.botOpenIdSource ?? { kind: "fetch" };
|
|
6812
6610
|
const botIdentity = botOpenIdSource.kind === "prefetched" ? {
|
|
6813
6611
|
botOpenId: botOpenIdSource.botOpenId,
|
|
6814
|
-
botName: botOpenIdSource.botName,
|
|
6815
6612
|
source: botOpenIdSource.source
|
|
6816
6613
|
} : await fetchBotIdentityForMonitor(account, {
|
|
6817
6614
|
runtime,
|
|
6818
6615
|
abortSignal
|
|
6819
6616
|
});
|
|
6820
|
-
const
|
|
6617
|
+
const botOpenId = applyBotIdentityState(accountId, botIdentity);
|
|
6821
6618
|
log(`feishu[${accountId}]: bot open_id resolved: ${botOpenId ?? "unknown"}`);
|
|
6822
6619
|
if ((!botOpenId || botIdentity.source === "cache") && !abortSignal?.aborted) startBotIdentityRecovery({
|
|
6823
6620
|
account,
|