@openclaw/whatsapp 2026.7.2-beta.3 → 2026.7.2-beta.5
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/README.md +1 -1
- package/dist/{access-control-tjy_em01.js → access-control-pZcxTmd5.js} +4 -5
- package/dist/{accounts-ejK8sXPU.js → accounts-CSqLvCY5.js} +1 -2
- package/dist/{action-runtime-p0V390gA.js → action-runtime-B2bNDUwE.js} +3 -3
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/{active-listener-BbdlXooT.js → active-listener-BEjWsCNM.js} +1 -1
- package/dist/api.js +13 -22
- package/dist/{approval-handler.runtime-BO1oJ-b8.js → approval-handler.runtime-CmtqgLSQ.js} +6 -6
- package/dist/{approval-reactions-CrZFAyf-.js → approval-reactions-Cu66aYdq.js} +4 -4
- package/dist/{auth-store-BQi9pZqQ.js → auth-store-DcEpIOmE.js} +4 -3
- package/dist/call-tool-api.js +4 -4
- package/dist/{channel-B2I4Opzb.js → channel-DcWBc3Hb.js} +39 -67
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-CPRQE-s3.js → channel-react-action-DUIkjl6w.js} +12 -15
- package/dist/{channel.runtime-CjkhQzk8.js → channel.runtime-Q5fJ2I2b.js} +5 -5
- package/dist/{channel.setup-BMWE9LmN.js → channel.setup-C_1u6HN6.js} +3 -6
- package/dist/{config-schema-BZ8h1hWA.js → config-schema-DARep0Nn.js} +7 -5
- package/dist/{connection-controller-HGaffeFb.js → connection-controller-BOB2MVKY.js} +8 -10
- package/dist/{connection-controller-runtime-context-9mEeAvu1.js → connection-controller-runtime-context-DG0tuYuw.js} +3 -3
- package/dist/contract-api.js +2 -2
- package/dist/{directory-config-BZ775eGX.js → directory-config-DalGrfGN.js} +7 -7
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-CwzVXKoE.js +10 -0
- package/dist/doctor-contract-api.js +35 -79
- package/dist/{group-session-key-Dh8WZun_.js → group-session-key-DVMZlO3x.js} +11 -6
- package/dist/{identity-D7L8LCuH.js → identity-CPrT5aEU.js} +2 -2
- package/dist/light-runtime-api.js +2 -2
- package/dist/{login-ifOXCBjo.js → login-CvY2Dhch.js} +6 -7
- package/dist/{login-qr-DUHzVH_Y.js → login-qr-Bncpb6js.js} +7 -8
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-_jqDKBXj.js → monitor-B7phZF9w.js} +427 -525
- package/dist/normalize-C7Hkc_vE.js +2 -0
- package/dist/{normalize-target-DSZnHkKF.js → normalize-target-CugRyONv.js} +6 -2
- package/dist/{question-reactions-C0qJ6wGA.js → question-reactions-CRsnyoMK.js} +1 -1
- package/dist/{resolve-outbound-target-BR97fAbB.js → resolve-outbound-target-1GqbT1uX.js} +1 -1
- package/dist/runtime-BLlToOi6.js +21 -0
- package/dist/runtime-api.js +10 -10
- package/dist/runtime-setter-api.js +1 -1
- package/dist/{send-SB-4JrVZ.js → send-BTXJAyK4.js} +40 -86
- package/dist/{send-api-BG0MgoFI.js → send-api-BY_AkSiB.js} +41 -35
- package/dist/{setup-finalize-Cc-4iWGj.js → setup-finalize-C-m-vCl9.js} +4 -4
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-DhnXEZir.js → setup-surface-BjvUbR6M.js} +3 -3
- package/dist/{setup-core-BbIgEl2M.js → shared-UcAwtJaq.js} +79 -57
- package/dist/{socket-close-jNGyZY4T.js → socket-close-DridEuzz.js} +5 -6
- package/dist/{targets-runtime-Bsh0HR9y.js → targets-runtime-TMk0lGuy.js} +133 -29
- package/dist/text-runtime-CaKLhowd.js +4 -0
- package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/utf8/index.js +29 -18
- package/node_modules/@protobufjs/utf8/package.json +2 -2
- package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
- package/node_modules/@thi.ng/bitstream/package.json +4 -4
- package/node_modules/@thi.ng/errors/package.json +4 -4
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +16 -6
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/audio-type/package.json +3 -2
- package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.min.js.map +3 -3
- package/node_modules/lru-cache/package.json +1 -1
- package/node_modules/music-metadata/lib/common/Util.d.ts +1 -1
- package/node_modules/music-metadata/lib/common/Util.js +7 -1
- package/node_modules/music-metadata/lib/id3v2/FrameHeader.js +23 -3
- package/node_modules/music-metadata/lib/id3v2/FrameParser.js +2 -2
- package/node_modules/music-metadata/lib/id3v2/ID3v2Token.js +1 -1
- package/node_modules/music-metadata/lib/mp4/AtomToken.js +38 -13
- package/node_modules/music-metadata/lib/mpeg/MpegParser.js +1 -1
- package/node_modules/music-metadata/package.json +6 -6
- package/node_modules/p-queue/dist/index.js +17 -6
- package/node_modules/p-queue/package.json +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.js +145 -188
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +33 -76
- package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.js +168 -208
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/index.d.ts +0 -8
- package/node_modules/protobufjs/package.json +2 -3
- package/node_modules/protobufjs/src/parse.js +3 -0
- package/node_modules/protobufjs/src/util/minimal.js +0 -3
- package/node_modules/typebox/build/compile/validator.d.mts +1 -4
- package/node_modules/typebox/build/guard/guard.d.mts +1 -1
- package/node_modules/typebox/build/guard/guard.mjs +5 -2
- package/node_modules/typebox/build/guard/string.mjs +16 -4
- package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
- package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
- package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
- package/node_modules/typebox/build/typebox.d.mts +1 -1
- package/node_modules/typebox/build/typebox.mjs +1 -1
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +29 -32
- package/node_modules/ws/lib/receiver.js +15 -32
- package/node_modules/ws/lib/websocket-server.js +4 -4
- package/node_modules/ws/lib/websocket.js +4 -4
- package/node_modules/ws/package.json +5 -1
- package/openclaw.plugin.json +138 -194
- package/package.json +21 -12
- package/dist/doctor-By3SB4lm.js +0 -48
- package/dist/normalize-C-Z16y7Q.js +0 -2
- package/dist/runtime-BfAdAEYT.js +0 -8
- package/dist/text-runtime-BTGkMN0o.js +0 -4
- package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
- package/node_modules/@protobufjs/inquire/LICENSE +0 -26
- package/node_modules/@protobufjs/inquire/README.md +0 -13
- package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
- package/node_modules/@protobufjs/inquire/index.js +0 -38
- package/node_modules/@protobufjs/inquire/package.json +0 -21
- package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
- package/npm-shrinkwrap.json +0 -958
|
@@ -1,42 +1,40 @@
|
|
|
1
|
-
import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-
|
|
2
|
-
import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation, u as resolveWhatsAppReactionLevel } from "./send-
|
|
3
|
-
import {
|
|
4
|
-
import { r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-
|
|
5
|
-
import { a as
|
|
6
|
-
import {
|
|
7
|
-
import { a as cacheInboundMessageMeta, i as buildQuotedMessageOptions, n as resolveWhatsAppGroupSessionRoute, o as lookupInboundMessageMeta, r as resolveWhatsAppLegacyGroupSessionKey } from "./group-session-key-
|
|
8
|
-
import { g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-
|
|
9
|
-
import { a as getSelfIdentity, c as resolveComparableIdentity, i as getReplyContext, n as getMentionIdentities, o as getSenderIdentity, r as getPrimaryIdentityId, s as identitiesOverlap, t as getComparableIdentityValues } from "./identity-
|
|
1
|
+
import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CSqLvCY5.js";
|
|
2
|
+
import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation, u as resolveWhatsAppReactionLevel } from "./send-BTXJAyK4.js";
|
|
3
|
+
import { i as getWhatsAppRuntime } from "./runtime-BLlToOi6.js";
|
|
4
|
+
import { r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-DG0tuYuw.js";
|
|
5
|
+
import { a as markdownToWhatsAppChunks, c as toWhatsappJid, l as toWhatsappJidWithLid, n as isSelfChatMode, o as resolveEquivalentWhatsAppDirectChatJids, r as jidToE164, s as resolveJidToE164 } from "./targets-runtime-TMk0lGuy.js";
|
|
6
|
+
import { t as normalizeE164 } from "./text-runtime-CaKLhowd.js";
|
|
7
|
+
import { a as cacheInboundMessageMeta, i as buildQuotedMessageOptions, n as resolveWhatsAppGroupSessionRoute, o as lookupInboundMessageMeta, r as resolveWhatsAppLegacyGroupSessionKey } from "./group-session-key-DVMZlO3x.js";
|
|
8
|
+
import { g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-DcEpIOmE.js";
|
|
9
|
+
import { a as getSelfIdentity, c as resolveComparableIdentity, i as getReplyContext, n as getMentionIdentities, o as getSenderIdentity, r as getPrimaryIdentityId, s as identitiesOverlap, t as getComparableIdentityValues } from "./identity-CPrT5aEU.js";
|
|
10
10
|
import { n as resolveWhatsAppGroupsConfigPath } from "./group-config-path-BGyzT9Lg.js";
|
|
11
|
-
import { a as waitForWaConnection, c as isWhatsAppSocketOperationTimeoutError, d as withWhatsAppSocketOperationTimeout, l as resolveWhatsAppSocketOperationTimeoutMs, r as createWaSocket, s as createWhatsAppSocketOperationTimeoutAdapter, u as resolveWhatsAppSocketTiming } from "./socket-close-
|
|
11
|
+
import { a as waitForWaConnection, c as isWhatsAppSocketOperationTimeoutError, d as withWhatsAppSocketOperationTimeout, l as resolveWhatsAppSocketOperationTimeoutMs, r as createWaSocket, s as createWhatsAppSocketOperationTimeoutAdapter, u as resolveWhatsAppSocketTiming } from "./socket-close-DridEuzz.js";
|
|
12
12
|
import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
|
|
13
13
|
import { t as BufferJSON } from "./session.runtime-Nsqaehbd.js";
|
|
14
|
-
import { c as requireWhatsAppInboundAdmission, i as resolveWhatsAppInboundPolicy, l as resolveWhatsAppGroupConversationId, o as buildDeprecatedFlatWhatsAppInboundAdmission, r as resolveWhatsAppCommandAuthorized, s as requireAdmittedWhatsAppInboundMessage, t as checkInboundAccessControl } from "./access-control-
|
|
15
|
-
import { _ as
|
|
16
|
-
import { c as computeBackoff, d as resolveReconnectPolicy, f as sleepWithAbort, l as newConnectionId, n as WHATSAPP_WATCHDOG_TIMEOUT_ERROR, r as WhatsAppConnectionController, s as DEFAULT_RECONNECT_POLICY, u as resolveHeartbeatSeconds } from "./connection-controller-
|
|
17
|
-
import { n as maybeResolveWhatsAppApprovalReaction } from "./approval-reactions-
|
|
18
|
-
import { t as maybeResolveWhatsAppQuestionReaction } from "./question-reactions-
|
|
19
|
-
import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
|
|
14
|
+
import { c as requireWhatsAppInboundAdmission, i as resolveWhatsAppInboundPolicy, l as resolveWhatsAppGroupConversationId, o as buildDeprecatedFlatWhatsAppInboundAdmission, r as resolveWhatsAppCommandAuthorized, s as requireAdmittedWhatsAppInboundMessage, t as checkInboundAccessControl } from "./access-control-pZcxTmd5.js";
|
|
15
|
+
import { _ as extractMediaKind, a as mayContainWhatsAppOutboundMention, b as hasInboundUserContent, c as DisconnectReason, d as normalizeMessageContent, f as describeReplyContext, g as extractLocationData, h as extractExternalAdReplyContext, i as addWhatsAppOutboundMentionsToContent, l as downloadMediaMessage, m as extractContextInfo, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as extractContactContext, r as normalizeWhatsAppSendResult, s as addWhatsAppImagePreviewFields, t as createWebSendApi, u as isJidGroup, v as extractMentionedJids, x as resolveInboundMediaMimetype, y as extractText } from "./send-api-BY_AkSiB.js";
|
|
16
|
+
import { c as computeBackoff, d as resolveReconnectPolicy, f as sleepWithAbort, l as newConnectionId, n as WHATSAPP_WATCHDOG_TIMEOUT_ERROR, r as WhatsAppConnectionController, s as DEFAULT_RECONNECT_POLICY, u as resolveHeartbeatSeconds } from "./connection-controller-BOB2MVKY.js";
|
|
17
|
+
import { n as maybeResolveWhatsAppApprovalReaction } from "./approval-reactions-Cu66aYdq.js";
|
|
18
|
+
import { t as maybeResolveWhatsAppQuestionReaction } from "./question-reactions-CRsnyoMK.js";
|
|
20
19
|
import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
21
20
|
import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
22
|
-
import {
|
|
21
|
+
import { createAckReactionHandle, createStatusReactionController, logAckFailure, removeAckReactionHandleAfterReply, shouldAckReactionForWhatsApp } from "openclaw/plugin-sdk/channel-feedback";
|
|
23
22
|
import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
|
|
24
23
|
import { getChildLogger } from "openclaw/plugin-sdk/logging-core";
|
|
25
24
|
import { resolveMarkdownTableMode as resolveMarkdownTableMode$1 } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
26
25
|
import { createSubsystemLogger, defaultRuntime, formatDurationPrecise, getChildLogger as getChildLogger$1, logVerbose, logVerbose as logVerbose$1, registerUnhandledRejectionHandler, shouldLogVerbose, shouldLogVerbose as shouldLogVerbose$1, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
27
26
|
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
28
|
-
import {
|
|
27
|
+
import { bindIngressLifecycleToReplyOptions, createChannelIngressMonitor, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
29
28
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
|
|
30
29
|
import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
|
|
31
30
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
32
|
-
import { LocalMediaAccessError, getDefaultLocalRoots, loadWebMedia as loadWebMedia$1, loadWebMediaRaw, optimizeImageToJpeg, optimizeImageToPng } from "openclaw/plugin-sdk/web-media";
|
|
33
31
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
34
|
-
import {
|
|
35
|
-
import { DEFAULT_ACCOUNT_ID
|
|
32
|
+
import { buildChannelInboundEventContext, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundEnvelope as formatInboundEnvelope$1, formatInboundMediaUnavailableText, formatLocationText, formatMediaPlaceholderText, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveInboundSessionEnvelopeContext, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
33
|
+
import { DEFAULT_ACCOUNT_ID, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
36
34
|
import { asDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
37
35
|
import { createHash } from "node:crypto";
|
|
36
|
+
import { fanInChannelIngressLifecycles } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
38
37
|
import { getSessionEntry, patchSessionEntry, resolveStorePath, resolveStorePath as resolveStorePath$1, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
|
|
39
|
-
import { buildChannelInboundEventContext, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundEnvelope as formatInboundEnvelope$1, formatInboundMediaUnavailableText, formatLocationText, hasVisibleInboundReplyDispatch, resolveInboundSessionEnvelopeContext, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
40
38
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
41
39
|
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
|
|
42
40
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
@@ -46,7 +44,7 @@ import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInbou
|
|
|
46
44
|
import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
47
45
|
import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
48
46
|
import { saveMediaStream } from "openclaw/plugin-sdk/media-store";
|
|
49
|
-
import { getRuntimeConfig as getRuntimeConfig$1
|
|
47
|
+
import { getRuntimeConfig as getRuntimeConfig$1 } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
50
48
|
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
51
49
|
import { buildMentionRegexes, implicitMentionKindWhen, normalizeMentionText, resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-mention-gating";
|
|
52
50
|
import { createConnectedChannelStatusPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
@@ -57,6 +55,7 @@ import { hasControlCommand, isControlCommandMessage, shouldComputeCommandAuthori
|
|
|
57
55
|
import { createInternalHookEvent, deriveInboundMessageHookContext, fireAndForgetBoundedHook, toInternalMessageReceivedContext, toPluginMessageContext, toPluginMessageReceivedEvent, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
|
|
58
56
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
59
57
|
import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
|
|
58
|
+
import { LocalMediaAccessError, getDefaultLocalRoots, loadWebMedia, loadWebMediaRaw, optimizeImageToJpeg, optimizeImageToPng } from "openclaw/plugin-sdk/web-media";
|
|
60
59
|
import { createChannelApiRetryRunner } from "openclaw/plugin-sdk/retry-runtime";
|
|
61
60
|
//#region extensions/whatsapp/src/inbound/message-aliases.ts
|
|
62
61
|
function normalizeQuoteSender(sender) {
|
|
@@ -128,6 +127,18 @@ function defineDeprecatedAliasAccessors(msg, descriptors) {
|
|
|
128
127
|
defineDeprecatedAccessors(msg, descriptors);
|
|
129
128
|
return msg;
|
|
130
129
|
}
|
|
130
|
+
function defineDeprecatedStructuredContextPayloadAlias(msg) {
|
|
131
|
+
const channelStructuredContext = msg.payload.channelStructuredContext ?? msg.payload.untrustedStructuredContext;
|
|
132
|
+
if (channelStructuredContext !== void 0) msg.payload.channelStructuredContext = channelStructuredContext;
|
|
133
|
+
Object.defineProperty(msg.payload, "untrustedStructuredContext", {
|
|
134
|
+
configurable: true,
|
|
135
|
+
enumerable: true,
|
|
136
|
+
get: () => msg.payload.channelStructuredContext,
|
|
137
|
+
set: (value) => {
|
|
138
|
+
msg.payload.channelStructuredContext = value;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
131
142
|
function defineDeprecatedAdmissionTopLevelAccessors(msg) {
|
|
132
143
|
let fallbackConversationId = msg.conversationId || msg.from;
|
|
133
144
|
let fallbackAccountId = msg.accountId;
|
|
@@ -179,6 +190,7 @@ function defineDeprecatedAdmissionTopLevelAccessors(msg) {
|
|
|
179
190
|
});
|
|
180
191
|
}
|
|
181
192
|
function withDeprecatedWebInboundMessageFlatAliases(msg) {
|
|
193
|
+
defineDeprecatedStructuredContextPayloadAlias(msg);
|
|
182
194
|
return defineDeprecatedAliasAccessors(defineDeprecatedAdmissionTopLevelAccessors(msg), {
|
|
183
195
|
id: {
|
|
184
196
|
get: () => msg.event.id,
|
|
@@ -324,9 +336,13 @@ function withDeprecatedWebInboundMessageFlatAliases(msg) {
|
|
|
324
336
|
get: () => msg.payload.media?.url,
|
|
325
337
|
set: (value) => setMediaField(msg, "url", value)
|
|
326
338
|
},
|
|
339
|
+
channelStructuredContext: {
|
|
340
|
+
get: () => msg.payload.channelStructuredContext,
|
|
341
|
+
set: (value) => msg.payload.channelStructuredContext = value
|
|
342
|
+
},
|
|
327
343
|
untrustedStructuredContext: {
|
|
328
|
-
get: () => msg.payload.
|
|
329
|
-
set: (value) => msg.payload.
|
|
344
|
+
get: () => msg.payload.channelStructuredContext,
|
|
345
|
+
set: (value) => msg.payload.channelStructuredContext = value
|
|
330
346
|
},
|
|
331
347
|
isBatched: {
|
|
332
348
|
get: () => msg.event.isBatched,
|
|
@@ -353,7 +369,7 @@ function normalizeLegacyFlatWebInboundMessage(msg) {
|
|
|
353
369
|
body: msg.body,
|
|
354
370
|
media,
|
|
355
371
|
location: msg.location,
|
|
356
|
-
|
|
372
|
+
channelStructuredContext: msg.channelStructuredContext ?? msg.untrustedStructuredContext
|
|
357
373
|
},
|
|
358
374
|
platform: {
|
|
359
375
|
chatJid: msg.chatId,
|
|
@@ -441,6 +457,8 @@ const WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES = 450;
|
|
|
441
457
|
const WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES = 5e3;
|
|
442
458
|
const WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
443
459
|
const WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS = 10080 * 60 * 1e3;
|
|
460
|
+
const WHATSAPP_DURABLE_INBOUND_PRUNE_INTERVAL_MS = 3600 * 1e3;
|
|
461
|
+
const WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION = 1;
|
|
444
462
|
function hashNamespacePart(value) {
|
|
445
463
|
return createHash("sha256").update(value).digest("hex").slice(0, 24);
|
|
446
464
|
}
|
|
@@ -466,59 +484,62 @@ function createWhatsAppDurableInboundQueue(accountId) {
|
|
|
466
484
|
stateDir: getWhatsAppRuntime().state.resolveStateDir()
|
|
467
485
|
});
|
|
468
486
|
}
|
|
469
|
-
/** Raw receive chokepoint: append first, then let the drain normalize and dispatch. */
|
|
470
|
-
async function enqueueWhatsAppDurableInbound(params) {
|
|
471
|
-
const facts = inspectWhatsAppIngressMessage(params.message);
|
|
472
|
-
const receivedAt = params.receivedAt ?? Date.now();
|
|
473
|
-
await params.queue.prune({
|
|
474
|
-
pendingTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
|
|
475
|
-
completedTtlMs: WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS,
|
|
476
|
-
failedTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
|
|
477
|
-
pendingMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES,
|
|
478
|
-
completedMaxEntries: WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES,
|
|
479
|
-
failedMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES
|
|
480
|
-
});
|
|
481
|
-
return await params.queue.enqueue(facts.eventId, {
|
|
482
|
-
message: serializeWhatsAppDurableInboundMessage(params.message),
|
|
483
|
-
upsertType: params.upsertType,
|
|
484
|
-
...params.skipStaleAppend === void 0 ? {} : { skipStaleAppend: params.skipStaleAppend },
|
|
485
|
-
...params.skipRecentOutboundEcho === void 0 ? {} : { skipRecentOutboundEcho: params.skipRecentOutboundEcho },
|
|
486
|
-
receivedAt,
|
|
487
|
-
...params.receiveOrder === void 0 ? {} : { receiveOrder: params.receiveOrder }
|
|
488
|
-
}, {
|
|
489
|
-
receivedAt,
|
|
490
|
-
laneKey: facts.laneKey
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
487
|
function resolveWhatsAppIngressNonRetryableFailure(error) {
|
|
494
488
|
return error instanceof WhatsAppIngressPermanentError ? {
|
|
495
489
|
reason: error.reason,
|
|
496
490
|
message: error.message
|
|
497
491
|
} : null;
|
|
498
492
|
}
|
|
499
|
-
/**
|
|
500
|
-
function
|
|
501
|
-
return
|
|
493
|
+
/** Shared monitor with per-conversation lanes and completion at reply-lane adoption. */
|
|
494
|
+
function createWhatsAppIngressMonitor(params) {
|
|
495
|
+
return createChannelIngressMonitor({
|
|
502
496
|
queue: params.queue,
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
497
|
+
inspect: (admission) => inspectWhatsAppIngressMessage(admission.message),
|
|
498
|
+
payload: {
|
|
499
|
+
version: WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION,
|
|
500
|
+
serialize: (admission, { receivedAt }) => ({
|
|
501
|
+
...admission,
|
|
502
|
+
message: serializeWhatsAppDurableInboundMessage(admission.message),
|
|
503
|
+
receivedAt
|
|
504
|
+
}),
|
|
505
|
+
deserialize: (payload) => ({
|
|
506
|
+
...payload,
|
|
507
|
+
message: deserializeWhatsAppDurableInboundMessage(payload.message)
|
|
508
|
+
}),
|
|
509
|
+
encode: ({ body }) => body,
|
|
510
|
+
decode: (payload) => ({
|
|
511
|
+
version: WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION,
|
|
512
|
+
body: payload
|
|
513
|
+
}),
|
|
514
|
+
createClaimError: (kind) => new WhatsAppIngressPermanentError(kind === "invalid-version" ? "invalid-payload" : "event-id-mismatch", kind === "invalid-version" ? "WhatsApp ingress row has an invalid payload version" : "WhatsApp ingress row identity does not match its transport message key")
|
|
506
515
|
},
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
516
|
+
deliver: (admission, lifecycle) => params.dispatch(admission, lifecycle),
|
|
517
|
+
pollIntervalMs: params.pollIntervalMs,
|
|
518
|
+
retention: {
|
|
519
|
+
pruneIntervalMs: WHATSAPP_DURABLE_INBOUND_PRUNE_INTERVAL_MS,
|
|
520
|
+
pendingTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
|
|
521
|
+
pendingMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES,
|
|
522
|
+
completedTtlMs: WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS,
|
|
523
|
+
completedMaxEntries: WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES,
|
|
524
|
+
failedTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
|
|
525
|
+
failedMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES
|
|
526
|
+
},
|
|
527
|
+
drain: {
|
|
528
|
+
resolveNonRetryableFailure: resolveWhatsAppIngressNonRetryableFailure,
|
|
529
|
+
deriveLaneKey: (record) => {
|
|
530
|
+
try {
|
|
531
|
+
return inspectWhatsAppIngressMessage(deserializeWhatsAppDurableInboundMessage(record.payload.message)).laneKey;
|
|
532
|
+
} catch {
|
|
533
|
+
return record.id;
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
...params.onLog ? { onLog: params.onLog } : {}
|
|
514
537
|
},
|
|
515
|
-
...params.onLog ? { onLog: params.onLog } : {},
|
|
516
538
|
...params.abortSignal ? { abortSignal: params.abortSignal } : {},
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
539
|
+
admissionMode: "while-running",
|
|
540
|
+
createStoppedError: () => /* @__PURE__ */ new Error("WhatsApp ingress monitor is stopped."),
|
|
541
|
+
...params.onError ? { onError: params.onError } : {},
|
|
542
|
+
...params.onActivityChange ? { onActivityChange: params.onActivityChange } : {}
|
|
522
543
|
});
|
|
523
544
|
}
|
|
524
545
|
//#endregion
|
|
@@ -738,6 +759,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
738
759
|
const pendingDebounceKeys = /* @__PURE__ */ new Set();
|
|
739
760
|
const activeInboundFlushes = /* @__PURE__ */ new Set();
|
|
740
761
|
const pendingMessageHandlers = /* @__PURE__ */ new Set();
|
|
762
|
+
let durableIngressActive = false;
|
|
741
763
|
const debounceWorkWaiters = /* @__PURE__ */ new Set();
|
|
742
764
|
const notifyDebounceWork = () => {
|
|
743
765
|
if (debounceWorkWaiters.size === 0) return;
|
|
@@ -759,7 +781,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
759
781
|
};
|
|
760
782
|
let nextReceiveOrder = 0;
|
|
761
783
|
const publishPendingWorkState = (at = Date.now()) => {
|
|
762
|
-
options.onPendingWorkChanged?.(pendingMessageHandlers.size + pendingDebounceKeys.size + activeInboundFlushes.size, at);
|
|
784
|
+
options.onPendingWorkChanged?.(pendingMessageHandlers.size + pendingDebounceKeys.size + activeInboundFlushes.size + (durableIngressActive ? 1 : 0), at);
|
|
763
785
|
};
|
|
764
786
|
const buildInboundDebounceKey = (msg) => {
|
|
765
787
|
const admission = requireWhatsAppInboundAdmission(msg);
|
|
@@ -774,48 +796,6 @@ async function attachWebInboxToSocket(options) {
|
|
|
774
796
|
if (timestampDiff !== 0) return timestampDiff;
|
|
775
797
|
return (a.receiveOrder ?? 0) - (b.receiveOrder ?? 0);
|
|
776
798
|
});
|
|
777
|
-
const buildFlushIngressLifecycle = (entries) => {
|
|
778
|
-
const lifecycles = entries.map((entry) => entry.turnAdoptionLifecycle).filter((lifecycle) => lifecycle !== void 0);
|
|
779
|
-
const [firstLifecycle] = lifecycles;
|
|
780
|
-
if (!firstLifecycle) return {
|
|
781
|
-
lifecycle: void 0,
|
|
782
|
-
settle: async () => {},
|
|
783
|
-
abandon: async () => {}
|
|
784
|
-
};
|
|
785
|
-
let handedOff = false;
|
|
786
|
-
const adoptAll = async () => {
|
|
787
|
-
for (const lifecycle of lifecycles) await lifecycle.onAdopted();
|
|
788
|
-
};
|
|
789
|
-
return {
|
|
790
|
-
lifecycle: {
|
|
791
|
-
abortSignal: lifecycles.length === 1 ? firstLifecycle.abortSignal : AbortSignal.any(lifecycles.map((lifecycle) => lifecycle.abortSignal)),
|
|
792
|
-
onAdopted: async () => {
|
|
793
|
-
handedOff = true;
|
|
794
|
-
await adoptAll();
|
|
795
|
-
},
|
|
796
|
-
onDeferred: () => {
|
|
797
|
-
handedOff = true;
|
|
798
|
-
for (const lifecycle of lifecycles) lifecycle.onDeferred();
|
|
799
|
-
},
|
|
800
|
-
onAdoptionFinalizing: () => {
|
|
801
|
-
for (const lifecycle of lifecycles) lifecycle.onAdoptionFinalizing();
|
|
802
|
-
},
|
|
803
|
-
onAbandoned: async () => {
|
|
804
|
-
handedOff = true;
|
|
805
|
-
await Promise.all(lifecycles.map((lifecycle) => Promise.resolve(lifecycle.onAbandoned())));
|
|
806
|
-
}
|
|
807
|
-
},
|
|
808
|
-
settle: async () => {
|
|
809
|
-
if (!handedOff) await adoptAll();
|
|
810
|
-
},
|
|
811
|
-
abandon: async () => {
|
|
812
|
-
if (!handedOff) {
|
|
813
|
-
handedOff = true;
|
|
814
|
-
await Promise.all(lifecycles.map((lifecycle) => Promise.resolve(lifecycle.onAbandoned())));
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
|
-
};
|
|
819
799
|
const debouncer = createInboundDebouncer({
|
|
820
800
|
debounceMs: inboundDebounceMs,
|
|
821
801
|
buildKey: (msg) => msg.debounceKey ?? buildInboundDebounceKey(msg),
|
|
@@ -832,7 +812,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
832
812
|
const orderedEntries = orderDebouncedInboundEntries(entries);
|
|
833
813
|
const last = orderedEntries.at(-1);
|
|
834
814
|
if (!last) return;
|
|
835
|
-
const { lifecycle, settle, abandon } =
|
|
815
|
+
const { lifecycle, settle, abandon } = fanInChannelIngressLifecycles(orderedEntries.map((entry) => entry.turnAdoptionLifecycle));
|
|
836
816
|
try {
|
|
837
817
|
if (orderedEntries.length === 1) {
|
|
838
818
|
await options.onMessage(attachWhatsAppIngressLifecycle(last, lifecycle));
|
|
@@ -1192,17 +1172,19 @@ async function attachWebInboxToSocket(options) {
|
|
|
1192
1172
|
const locationText = location ? formatLocationText(location) : void 0;
|
|
1193
1173
|
const contactContext = extractContactContext(msg.message ?? void 0);
|
|
1194
1174
|
const externalAdReplyContext = extractExternalAdReplyContext(msg.message ?? void 0);
|
|
1195
|
-
|
|
1175
|
+
let mediaKind = extractMediaKind(msg.message ?? void 0);
|
|
1196
1176
|
let body = extractText(msg.message ?? void 0);
|
|
1197
1177
|
if (locationText) body = [body, locationText].filter(Boolean).join("\n").trim();
|
|
1198
|
-
if (!body)
|
|
1199
|
-
|
|
1200
|
-
if (!body) return null;
|
|
1201
|
-
}
|
|
1178
|
+
if (!body && !mediaKind) return null;
|
|
1179
|
+
body = body ?? "";
|
|
1202
1180
|
const commandBody = body;
|
|
1203
1181
|
const replyContext = describeReplyContext(msg.message);
|
|
1204
1182
|
let mediaPath;
|
|
1205
|
-
let mediaType;
|
|
1183
|
+
let mediaType = mediaKind ? resolveInboundMediaMimetype(msg.message) : void 0;
|
|
1184
|
+
const nativeMedia = mediaKind ? {
|
|
1185
|
+
contentType: mediaType,
|
|
1186
|
+
kind: mediaKind
|
|
1187
|
+
} : void 0;
|
|
1206
1188
|
let mediaFileName;
|
|
1207
1189
|
const maxBytes = (typeof options.mediaMaxMb === "number" && options.mediaMaxMb > 0 ? options.mediaMaxMb : 50) * 1024 * 1024;
|
|
1208
1190
|
const saveInboundMedia = async (inboundMedia) => {
|
|
@@ -1217,12 +1199,13 @@ async function attachWebInboxToSocket(options) {
|
|
|
1217
1199
|
logWhatsAppVerbose(options.verbose, `Inbound media download failed: ${String(err)}`);
|
|
1218
1200
|
body = formatInboundMediaUnavailableText({
|
|
1219
1201
|
body,
|
|
1220
|
-
mediaPlaceholder,
|
|
1221
1202
|
notice: "[whatsapp attachment unavailable]"
|
|
1222
1203
|
});
|
|
1223
1204
|
}
|
|
1224
|
-
if (!mediaPath && replyContext) try {
|
|
1205
|
+
if (!mediaPath && !mediaKind && replyContext?.media) try {
|
|
1225
1206
|
await saveInboundMedia(await downloadQuotedInboundMedia(msg, sock, maxBytes));
|
|
1207
|
+
mediaKind = replyContext.media.kind ?? void 0;
|
|
1208
|
+
mediaType = mediaType ?? replyContext.media.contentType ?? void 0;
|
|
1226
1209
|
} catch (err) {
|
|
1227
1210
|
logWhatsAppVerbose(options.verbose, `Quoted media download failed: ${String(err)}`);
|
|
1228
1211
|
body = formatInboundMediaUnavailableText({
|
|
@@ -1239,7 +1222,9 @@ async function attachWebInboxToSocket(options) {
|
|
|
1239
1222
|
replyContext,
|
|
1240
1223
|
mediaPath,
|
|
1241
1224
|
mediaType,
|
|
1242
|
-
mediaFileName
|
|
1225
|
+
mediaFileName,
|
|
1226
|
+
mediaKind,
|
|
1227
|
+
nativeMedia
|
|
1243
1228
|
};
|
|
1244
1229
|
};
|
|
1245
1230
|
const enqueueInboundMessage = async (msg, inbound, enriched, durable) => {
|
|
@@ -1274,10 +1259,11 @@ async function attachWebInboxToSocket(options) {
|
|
|
1274
1259
|
mediaFileName: enriched.mediaFileName,
|
|
1275
1260
|
timestamp
|
|
1276
1261
|
}, "inbound message");
|
|
1277
|
-
const media = enriched.mediaPath || enriched.mediaType || enriched.mediaFileName ? {
|
|
1262
|
+
const media = enriched.mediaPath || enriched.mediaType || enriched.mediaFileName || enriched.mediaKind ? {
|
|
1278
1263
|
path: enriched.mediaPath,
|
|
1279
1264
|
type: enriched.mediaType,
|
|
1280
|
-
fileName: enriched.mediaFileName
|
|
1265
|
+
fileName: enriched.mediaFileName,
|
|
1266
|
+
kind: enriched.mediaKind
|
|
1281
1267
|
} : void 0;
|
|
1282
1268
|
const groupMentions = mentionedJids ? { jids: mentionedJids } : void 0;
|
|
1283
1269
|
const group = inbound.group && (inbound.groupSubject || inbound.groupParticipants?.length || groupMentions) ? {
|
|
@@ -1285,17 +1271,26 @@ async function attachWebInboxToSocket(options) {
|
|
|
1285
1271
|
participants: inbound.groupParticipants,
|
|
1286
1272
|
mentions: groupMentions
|
|
1287
1273
|
} : void 0;
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1274
|
+
const channelStructuredContext = [
|
|
1275
|
+
...enriched.nativeMedia ? [{
|
|
1276
|
+
label: "WhatsApp media",
|
|
1277
|
+
source: "whatsapp",
|
|
1278
|
+
type: "media",
|
|
1279
|
+
payload: enriched.nativeMedia
|
|
1280
|
+
}] : [],
|
|
1281
|
+
...enriched.contactContext ? [{
|
|
1282
|
+
label: "WhatsApp contact",
|
|
1283
|
+
source: "whatsapp",
|
|
1284
|
+
type: enriched.contactContext.kind,
|
|
1285
|
+
payload: enriched.contactContext
|
|
1286
|
+
}] : [],
|
|
1287
|
+
...enriched.externalAdReplyContext ? [{
|
|
1288
|
+
label: "WhatsApp external ad reply",
|
|
1289
|
+
source: "whatsapp",
|
|
1290
|
+
type: "external_ad_reply",
|
|
1291
|
+
payload: enriched.externalAdReplyContext
|
|
1292
|
+
}] : []
|
|
1293
|
+
];
|
|
1299
1294
|
const inboundMessage = withDeprecatedWebInboundMessageFlatAliases({
|
|
1300
1295
|
admission: inbound.access.admission,
|
|
1301
1296
|
event: {
|
|
@@ -1306,7 +1301,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1306
1301
|
body: enriched.body,
|
|
1307
1302
|
commandBody: enriched.commandBody,
|
|
1308
1303
|
location: enriched.location ?? void 0,
|
|
1309
|
-
|
|
1304
|
+
channelStructuredContext: channelStructuredContext.length > 0 ? channelStructuredContext : void 0,
|
|
1310
1305
|
media
|
|
1311
1306
|
},
|
|
1312
1307
|
platform: {
|
|
@@ -1334,6 +1329,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1334
1329
|
context: enriched.replyContext,
|
|
1335
1330
|
id: enriched.replyContext.id,
|
|
1336
1331
|
body: enriched.replyContext.body,
|
|
1332
|
+
media: enriched.replyContext.media,
|
|
1337
1333
|
sender: {
|
|
1338
1334
|
displayName: enriched.replyContext.sender?.label ?? void 0,
|
|
1339
1335
|
jid: enriched.replyContext.sender?.jid ?? void 0,
|
|
@@ -1360,16 +1356,21 @@ async function attachWebInboxToSocket(options) {
|
|
|
1360
1356
|
participant: inboundMessage.platform.senderJid,
|
|
1361
1357
|
participantE164: admission.conversation.kind === "direct" ? inboundMessage.platform.senderE164 : void 0,
|
|
1362
1358
|
body: inboundMessage.payload.body,
|
|
1359
|
+
media: enriched.nativeMedia,
|
|
1363
1360
|
fromMe: inboundMessage.platform.fromMe
|
|
1364
1361
|
});
|
|
1365
1362
|
}
|
|
1366
1363
|
await debouncer.enqueue(inboundMessage);
|
|
1367
1364
|
};
|
|
1368
|
-
const
|
|
1365
|
+
const processDurableInboundMessage = async (admission, lifecycle) => {
|
|
1366
|
+
const { message: msg, ...context } = admission;
|
|
1369
1367
|
rememberBaileysMessage(msg.key?.remoteJid, msg.key?.id, msg.message);
|
|
1368
|
+
const remoteJid = msg.key?.remoteJid;
|
|
1369
|
+
const id = msg.key?.id;
|
|
1370
|
+
const durableId = remoteJid && id ? createHash("sha256").update(`${remoteJid}\n${id}`).digest("hex") : void 0;
|
|
1371
|
+
const preparation = durableId ? preparedInboundByDurableId.get(durableId) : void 0;
|
|
1372
|
+
if (durableId) preparedInboundByDurableId.delete(durableId);
|
|
1370
1373
|
if (context.skipRecentOutboundEcho === true) return "completed";
|
|
1371
|
-
const preparation = context.eventId ? preparedInboundByDurableId.get(context.eventId) : void 0;
|
|
1372
|
-
if (context.eventId) preparedInboundByDurableId.delete(context.eventId);
|
|
1373
1374
|
const prepared = await preparation;
|
|
1374
1375
|
if (prepared === null) return "completed";
|
|
1375
1376
|
const inbound = prepared ?? await normalizeInboundMessage(msg);
|
|
@@ -1397,85 +1398,21 @@ async function attachWebInboxToSocket(options) {
|
|
|
1397
1398
|
await enqueueInboundMessage(msg, inbound, enriched, {
|
|
1398
1399
|
readReceipt: deliveryReadReceipt,
|
|
1399
1400
|
receiveOrder: context.receiveOrder ?? context.receivedAt,
|
|
1400
|
-
turnAdoptionLifecycle:
|
|
1401
|
+
turnAdoptionLifecycle: lifecycle
|
|
1401
1402
|
});
|
|
1402
1403
|
return "deferred";
|
|
1403
1404
|
};
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
const task = (async () => {
|
|
1413
|
-
await durableInboundDrain.recoverStaleClaims();
|
|
1414
|
-
while (durableDrainRequested) {
|
|
1415
|
-
durableDrainRequested = false;
|
|
1416
|
-
if ((await durableInboundDrain.drainOnce()).started > 0) {
|
|
1417
|
-
await durableInboundDrain.waitForIdle();
|
|
1418
|
-
durableDrainRequested = true;
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
})().catch((error) => {
|
|
1422
|
-
passFailed = true;
|
|
1423
|
-
throw error;
|
|
1424
|
-
});
|
|
1425
|
-
durableDrainPass = task;
|
|
1426
|
-
pendingMessageHandlers.add(task);
|
|
1405
|
+
const durableInboundMonitor = createWhatsAppIngressMonitor({
|
|
1406
|
+
queue: durableInboundQueue,
|
|
1407
|
+
dispatch: async (admission, lifecycle) => ({ kind: await processDurableInboundMessage(admission, lifecycle) }),
|
|
1408
|
+
pollIntervalMs: WHATSAPP_INGRESS_DRAIN_INTERVAL_MS,
|
|
1409
|
+
onLog: (message) => inboundLogger.warn({ message }, "whatsapp ingress drain"),
|
|
1410
|
+
onError: (error) => inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed"),
|
|
1411
|
+
onActivityChange: (active) => {
|
|
1412
|
+
durableIngressActive = active;
|
|
1427
1413
|
publishPendingWorkState();
|
|
1428
|
-
task.finally(() => {
|
|
1429
|
-
if (durableDrainPass === task) durableDrainPass = void 0;
|
|
1430
|
-
pendingMessageHandlers.delete(task);
|
|
1431
|
-
publishPendingWorkState();
|
|
1432
|
-
if (durableDrainRequested && !passFailed) requestDurableInboundDrain().catch((error) => {
|
|
1433
|
-
inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed");
|
|
1434
|
-
});
|
|
1435
|
-
}).catch(() => void 0);
|
|
1436
|
-
}
|
|
1437
|
-
return durableDrainPass;
|
|
1438
|
-
};
|
|
1439
|
-
const requestDrainAfterLaneSettlement = () => {
|
|
1440
|
-
requestDurableInboundDrain().catch((error) => {
|
|
1441
|
-
inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed");
|
|
1442
|
-
});
|
|
1443
|
-
};
|
|
1444
|
-
const continueDrainAfterLaneSettlement = (lifecycle) => ({
|
|
1445
|
-
abortSignal: lifecycle.abortSignal,
|
|
1446
|
-
onAdopted: async () => {
|
|
1447
|
-
await lifecycle.onAdopted();
|
|
1448
|
-
requestDrainAfterLaneSettlement();
|
|
1449
|
-
},
|
|
1450
|
-
onDeferred: lifecycle.onDeferred,
|
|
1451
|
-
onAdoptionFinalizing: lifecycle.onAdoptionFinalizing,
|
|
1452
|
-
onAbandoned: async () => {
|
|
1453
|
-
await lifecycle.onAbandoned();
|
|
1454
|
-
requestDrainAfterLaneSettlement();
|
|
1455
1414
|
}
|
|
1456
1415
|
});
|
|
1457
|
-
const durableInboundDrain = createWhatsAppIngressDrain({
|
|
1458
|
-
queue: durableInboundQueue,
|
|
1459
|
-
dispatch: async (msg, payload, lifecycle) => {
|
|
1460
|
-
const remoteJid = msg.key?.remoteJid;
|
|
1461
|
-
const id = msg.key?.id;
|
|
1462
|
-
return { kind: await processWhatsAppInboundMessage(msg, {
|
|
1463
|
-
...payload,
|
|
1464
|
-
...remoteJid && id ? { eventId: createWhatsAppDurableInboundMessageId({
|
|
1465
|
-
remoteJid,
|
|
1466
|
-
id
|
|
1467
|
-
}) } : {},
|
|
1468
|
-
lifecycle: continueDrainAfterLaneSettlement(lifecycle)
|
|
1469
|
-
}) };
|
|
1470
|
-
},
|
|
1471
|
-
onLog: (message) => inboundLogger.warn({ message }, "whatsapp ingress drain")
|
|
1472
|
-
});
|
|
1473
|
-
const durableDrainTimer = setInterval(() => {
|
|
1474
|
-
requestDurableInboundDrain().catch((error) => {
|
|
1475
|
-
inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed");
|
|
1476
|
-
});
|
|
1477
|
-
}, WHATSAPP_INGRESS_DRAIN_INTERVAL_MS);
|
|
1478
|
-
durableDrainTimer.unref?.();
|
|
1479
1416
|
const handleMessagesUpsert = async (upsert) => {
|
|
1480
1417
|
if (upsert.type !== "notify" && upsert.type !== "append") return;
|
|
1481
1418
|
for (const msg of upsert.messages ?? []) {
|
|
@@ -1496,10 +1433,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1496
1433
|
const skipRecentOutboundEcho = shouldSkipRecentOutboundEcho(msg);
|
|
1497
1434
|
const remoteJid = msg.key?.remoteJid;
|
|
1498
1435
|
const id = msg.key?.id;
|
|
1499
|
-
const durableId = remoteJid && id ?
|
|
1500
|
-
remoteJid,
|
|
1501
|
-
id
|
|
1502
|
-
}) : void 0;
|
|
1436
|
+
const durableId = remoteJid && id ? createHash("sha256").update(`${remoteJid}\n${id}`).digest("hex") : void 0;
|
|
1503
1437
|
let resolvePrepared;
|
|
1504
1438
|
if (durableId && !preparedInboundByDurableId.has(durableId)) {
|
|
1505
1439
|
if (preparedInboundByDurableId.size >= 1e3) {
|
|
@@ -1515,54 +1449,34 @@ async function attachWebInboxToSocket(options) {
|
|
|
1515
1449
|
if (!keepForDrain && durableId && resolvePrepared) preparedInboundByDurableId.delete(durableId);
|
|
1516
1450
|
};
|
|
1517
1451
|
let result;
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
});
|
|
1527
|
-
|
|
1528
|
-
result = await enqueueWhatsAppDurableInbound({
|
|
1529
|
-
queue: durableInboundQueue,
|
|
1530
|
-
message: msg,
|
|
1531
|
-
upsertType: upsert.type,
|
|
1532
|
-
skipStaleAppend,
|
|
1533
|
-
skipRecentOutboundEcho,
|
|
1534
|
-
receivedAt,
|
|
1535
|
-
receiveOrder
|
|
1536
|
-
});
|
|
1537
|
-
appendError = void 0;
|
|
1538
|
-
break;
|
|
1539
|
-
} catch (error) {
|
|
1540
|
-
appendError = error;
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
if (result === void 0) {
|
|
1452
|
+
try {
|
|
1453
|
+
result = await durableInboundMonitor.admit({
|
|
1454
|
+
message: msg,
|
|
1455
|
+
upsertType: upsert.type,
|
|
1456
|
+
skipStaleAppend,
|
|
1457
|
+
skipRecentOutboundEcho,
|
|
1458
|
+
receivedAt,
|
|
1459
|
+
receiveOrder
|
|
1460
|
+
}, { receivedAt });
|
|
1461
|
+
} catch (error) {
|
|
1544
1462
|
finishPreparation(void 0);
|
|
1545
|
-
const formattedError = formatError(
|
|
1463
|
+
const formattedError = formatError(error);
|
|
1546
1464
|
inboundLogger.error({ error: formattedError }, "failed persisting durable WhatsApp inbound after retries; message dropped");
|
|
1547
1465
|
inboundConsoleLog.error(`Failed persisting durable WhatsApp inbound after retries; message dropped: ${formattedError}`);
|
|
1548
1466
|
continue;
|
|
1549
1467
|
}
|
|
1550
|
-
if (result.kind === "completed") {
|
|
1468
|
+
if (result.kind === "durable" && result.queueResult.kind === "completed") {
|
|
1551
1469
|
finishPreparation(void 0);
|
|
1552
1470
|
const inbound = await normalizeInboundMessage(msg);
|
|
1553
1471
|
if (inbound) await maybeMarkNonSelfChatReadReceipt(inbound, buildReadReceiptTarget(inbound));
|
|
1554
|
-
} else
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
}
|
|
1561
|
-
else finishPreparation(void 0);
|
|
1562
|
-
requestDurableInboundDrain().catch((error) => {
|
|
1563
|
-
inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed");
|
|
1564
|
-
});
|
|
1472
|
+
} else if (result.kind === "durable" && result.queueResult.kind === "accepted") if (skipRecentOutboundEcho) finishPreparation(null);
|
|
1473
|
+
else try {
|
|
1474
|
+
finishPreparation(await normalizeInboundMessage(msg), true);
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
finishPreparation(void 0);
|
|
1477
|
+
inboundLogger.warn({ error: formatError(error) }, "failed preparing WhatsApp inbound identity; durable drain will normalize again");
|
|
1565
1478
|
}
|
|
1479
|
+
else finishPreparation(void 0);
|
|
1566
1480
|
}
|
|
1567
1481
|
};
|
|
1568
1482
|
const handleMessagesUpsertEvent = (upsert) => {
|
|
@@ -1588,7 +1502,6 @@ async function attachWebInboxToSocket(options) {
|
|
|
1588
1502
|
};
|
|
1589
1503
|
const drainInboundBeforeSocketClose = async () => {
|
|
1590
1504
|
groupMetadataCacheClosed = true;
|
|
1591
|
-
clearInterval(durableDrainTimer);
|
|
1592
1505
|
for (;;) {
|
|
1593
1506
|
await drainDebouncedInboundMessages();
|
|
1594
1507
|
if (pendingMessageHandlers.size === 0) break;
|
|
@@ -1597,12 +1510,12 @@ async function attachWebInboxToSocket(options) {
|
|
|
1597
1510
|
if (pendingMessageHandlers.size === 0 && pendingDebounceKeys.size === 0 && activeInboundFlushes.size === 0) break;
|
|
1598
1511
|
}
|
|
1599
1512
|
await drainDebouncedInboundMessages();
|
|
1600
|
-
|
|
1601
|
-
await
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
durableInboundDrain.dispose();
|
|
1513
|
+
for (;;) {
|
|
1514
|
+
await durableInboundMonitor.waitForIdle();
|
|
1515
|
+
if (pendingDebounceKeys.size === 0 && activeInboundFlushes.size === 0) break;
|
|
1516
|
+
await drainDebouncedInboundMessages();
|
|
1605
1517
|
}
|
|
1518
|
+
await durableInboundMonitor.stop();
|
|
1606
1519
|
};
|
|
1607
1520
|
const drainInboundBeforeSocketCloseWithTimeout = async () => {
|
|
1608
1521
|
let timeout = null;
|
|
@@ -1615,8 +1528,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1615
1528
|
})]);
|
|
1616
1529
|
} finally {
|
|
1617
1530
|
if (timeout) clearTimeout(timeout);
|
|
1618
|
-
|
|
1619
|
-
durableInboundDrain.dispose();
|
|
1531
|
+
durableInboundMonitor.stop();
|
|
1620
1532
|
}
|
|
1621
1533
|
};
|
|
1622
1534
|
const handleConnectionUpdate = (update) => {
|
|
@@ -1675,10 +1587,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1675
1587
|
const detachGroupParticipantsUpdate = attachSockListener("group-participants.update", ((update) => {
|
|
1676
1588
|
forgetFullGroupMetadata(update.id);
|
|
1677
1589
|
}));
|
|
1678
|
-
|
|
1679
|
-
inboundLogger.error({ error: String(err) }, "failed replaying durable WhatsApp inbound");
|
|
1680
|
-
inboundConsoleLog.error(`Failed replaying durable WhatsApp inbound: ${String(err)}`);
|
|
1681
|
-
});
|
|
1590
|
+
durableInboundMonitor.start();
|
|
1682
1591
|
(async () => {
|
|
1683
1592
|
try {
|
|
1684
1593
|
const groups = await sock.groupFetchAllParticipating();
|
|
@@ -1736,7 +1645,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1736
1645
|
};
|
|
1737
1646
|
}
|
|
1738
1647
|
async function monitorWebInbox(options) {
|
|
1739
|
-
const socketTiming = options.socketTiming ?? resolveWhatsAppSocketTiming(
|
|
1648
|
+
const socketTiming = options.socketTiming ?? resolveWhatsAppSocketTiming();
|
|
1740
1649
|
const recentMessageKeys = options.recentMessageKeys ?? /* @__PURE__ */ new Map();
|
|
1741
1650
|
const baileysGroupMetaCache = options.baileysGroupMetaCache ?? /* @__PURE__ */ new Map();
|
|
1742
1651
|
const sock = await createWaSocket(false, options.verbose, {
|
|
@@ -1794,12 +1703,13 @@ function isBotMentionedFromTargets(msg, mentionCfg, targets) {
|
|
|
1794
1703
|
const isGroupConversation = requireWhatsAppInboundAdmission(msg).conversation.kind === "group";
|
|
1795
1704
|
const isSelfChat = explicitSelfChatOverride ? Boolean(mentionCfg.isSelfChat) : isSelfChatMode(targets.self.e164, mentionCfg.allowFrom) && !isGroupConversation;
|
|
1796
1705
|
const hasMentions = targets.normalizedMentions.length > 0;
|
|
1797
|
-
|
|
1706
|
+
const hasNativeMentionsOutsideSelfChat = hasMentions && !isSelfChat;
|
|
1707
|
+
if (hasNativeMentionsOutsideSelfChat) {
|
|
1798
1708
|
for (const mention of targets.normalizedMentions) if (identitiesOverlap(targets.self, mention)) return true;
|
|
1799
|
-
return false;
|
|
1800
1709
|
} else if (hasMentions && isSelfChat) {}
|
|
1801
1710
|
const bodyClean = clean(msg.payload.body);
|
|
1802
1711
|
if (mentionCfg.mentionRegexes.some((re) => re.test(bodyClean))) return true;
|
|
1712
|
+
if (hasNativeMentionsOutsideSelfChat) return false;
|
|
1803
1713
|
if (targets.self.e164) {
|
|
1804
1714
|
const selfDigits = targets.self.e164.replace(/\D/g, "");
|
|
1805
1715
|
if (selfDigits) {
|
|
@@ -1980,8 +1890,7 @@ function formatWhatsAppInboundListeningLog(account) {
|
|
|
1980
1890
|
const DEFAULT_WHATSAPP_ACK_REACTION = "👀";
|
|
1981
1891
|
function resolveWhatsAppAckEmoji(params) {
|
|
1982
1892
|
if (!params.ackConfig) return "";
|
|
1983
|
-
|
|
1984
|
-
return resolveAgentIdentityEmoji(params.cfg, params.agentId) ?? DEFAULT_WHATSAPP_ACK_REACTION;
|
|
1893
|
+
return (typeof params.ackConfig === "string" ? params.ackConfig : params.ackConfig.emoji)?.trim() || resolveAgentIdentityEmoji(params.cfg, params.agentId) || DEFAULT_WHATSAPP_ACK_REACTION;
|
|
1985
1894
|
}
|
|
1986
1895
|
function resolveAgentIdentityEmoji(cfg, agentId) {
|
|
1987
1896
|
return resolveAgentIdentity(cfg, agentId)?.emoji?.trim() || void 0;
|
|
@@ -1989,7 +1898,7 @@ function resolveAgentIdentityEmoji(cfg, agentId) {
|
|
|
1989
1898
|
//#endregion
|
|
1990
1899
|
//#region extensions/whatsapp/src/auto-reply/monitor/group-activation.ts
|
|
1991
1900
|
function hasNamedWhatsAppAccounts(cfg) {
|
|
1992
|
-
return Object.keys(cfg.channels?.whatsapp?.accounts ?? {}).some((accountId) => normalizeAccountId
|
|
1901
|
+
return Object.keys(cfg.channels?.whatsapp?.accounts ?? {}).some((accountId) => normalizeAccountId(accountId) !== DEFAULT_ACCOUNT_ID);
|
|
1993
1902
|
}
|
|
1994
1903
|
function isActivationOnlyEntry(entry) {
|
|
1995
1904
|
return entry?.groupActivation !== void 0 && typeof entry?.sessionId !== "string" && typeof entry?.updatedAt !== "number";
|
|
@@ -2012,7 +1921,7 @@ async function resolveGroupActivationFor(params) {
|
|
|
2012
1921
|
...sessionScope,
|
|
2013
1922
|
sessionKey: params.sessionKey
|
|
2014
1923
|
});
|
|
2015
|
-
const activation = (normalizeAccountId
|
|
1924
|
+
const activation = (normalizeAccountId(params.accountId) === DEFAULT_ACCOUNT_ID && hasNamedWhatsAppAccounts(params.cfg) && isActivationOnlyEntry(scopedEntry) ? void 0 : scopedEntry?.groupActivation) ?? legacyEntry?.groupActivation;
|
|
2016
1925
|
if (activation !== void 0 && scopedEntry?.groupActivation === void 0) {
|
|
2017
1926
|
if (scopedEntry) await patchSessionEntry({
|
|
2018
1927
|
...sessionScope,
|
|
@@ -2034,33 +1943,41 @@ async function resolveGroupActivationFor(params) {
|
|
|
2034
1943
|
return normalizeGroupActivation(activation) ?? defaultActivation;
|
|
2035
1944
|
}
|
|
2036
1945
|
//#endregion
|
|
2037
|
-
//#region extensions/whatsapp/src/auto-reply/monitor/
|
|
2038
|
-
|
|
2039
|
-
|
|
1946
|
+
//#region extensions/whatsapp/src/auto-reply/monitor/reaction-participant.ts
|
|
1947
|
+
function resolveReactionParticipant(msg) {
|
|
1948
|
+
const sender = getSenderIdentity(msg);
|
|
1949
|
+
return sender.jid ?? sender.lid ?? void 0;
|
|
1950
|
+
}
|
|
1951
|
+
//#endregion
|
|
1952
|
+
//#region extensions/whatsapp/src/auto-reply/monitor/reaction-eligibility.ts
|
|
1953
|
+
const DISABLED_REACTION = { status: "disabled" };
|
|
1954
|
+
async function resolveWhatsAppReactionEligibility(params) {
|
|
1955
|
+
const messageId = params.msg.event.id;
|
|
1956
|
+
if (!messageId) return DISABLED_REACTION;
|
|
2040
1957
|
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
2041
1958
|
const accountId = admission.accountId;
|
|
2042
1959
|
if (resolveWhatsAppReactionLevel({
|
|
2043
1960
|
cfg: params.cfg,
|
|
2044
1961
|
accountId
|
|
2045
|
-
}).level === "off") return
|
|
2046
|
-
const
|
|
1962
|
+
}).level === "off") return DISABLED_REACTION;
|
|
1963
|
+
const scope = params.cfg.messages?.ackReactionScope ?? "group-mentions";
|
|
1964
|
+
if (scope === "off" || scope === "none") return DISABLED_REACTION;
|
|
2047
1965
|
const emoji = resolveWhatsAppAckEmoji({
|
|
2048
1966
|
cfg: params.cfg,
|
|
2049
1967
|
agentId: params.agentId,
|
|
2050
|
-
ackConfig
|
|
1968
|
+
ackConfig: params.cfg.messages?.ackReaction
|
|
2051
1969
|
});
|
|
2052
|
-
const directEnabled =
|
|
2053
|
-
const groupMode =
|
|
1970
|
+
const directEnabled = scope === "all" || scope === "direct";
|
|
1971
|
+
const groupMode = scope === "all" || scope === "group-all" ? "always" : scope === "direct" ? "never" : "mentions";
|
|
2054
1972
|
const isGroup = admission.conversation.kind === "group";
|
|
2055
|
-
const conversationIdForCheck = admission.conversation.id;
|
|
2056
1973
|
const activation = isGroup ? await resolveGroupActivationFor({
|
|
2057
1974
|
cfg: params.cfg,
|
|
2058
1975
|
accountId,
|
|
2059
1976
|
agentId: params.agentId,
|
|
2060
1977
|
sessionKey: params.sessionKey,
|
|
2061
|
-
conversationId:
|
|
1978
|
+
conversationId: admission.conversation.id
|
|
2062
1979
|
}) : null;
|
|
2063
|
-
|
|
1980
|
+
if (!shouldAckReactionForWhatsApp({
|
|
2064
1981
|
emoji,
|
|
2065
1982
|
isDirect: admission.conversation.kind === "direct",
|
|
2066
1983
|
isGroup,
|
|
@@ -2068,32 +1985,50 @@ async function maybeSendAckReaction(params) {
|
|
|
2068
1985
|
groupMode,
|
|
2069
1986
|
wasMentioned: (params.msg.groupMention?.wasMentioned ?? params.msg.wasMentioned) === true,
|
|
2070
1987
|
groupActivated: activation === "always"
|
|
1988
|
+
})) return DISABLED_REACTION;
|
|
1989
|
+
const participant = resolveReactionParticipant(params.msg);
|
|
1990
|
+
return {
|
|
1991
|
+
status: "prepared",
|
|
1992
|
+
chatId: params.msg.platform.chatJid,
|
|
1993
|
+
messageId,
|
|
1994
|
+
emoji,
|
|
1995
|
+
reactionOptions: {
|
|
1996
|
+
verbose: params.verbose,
|
|
1997
|
+
fromMe: false,
|
|
1998
|
+
...participant ? { participant } : {},
|
|
1999
|
+
accountId,
|
|
2000
|
+
cfg: params.cfg
|
|
2001
|
+
}
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
//#endregion
|
|
2005
|
+
//#region extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts
|
|
2006
|
+
async function maybeSendAckReaction(params) {
|
|
2007
|
+
const eligibility = await resolveWhatsAppReactionEligibility({
|
|
2008
|
+
cfg: params.cfg,
|
|
2009
|
+
msg: params.msg,
|
|
2010
|
+
agentId: params.agentId,
|
|
2011
|
+
sessionKey: params.sessionKey,
|
|
2012
|
+
verbose: params.verbose
|
|
2071
2013
|
});
|
|
2072
|
-
if (
|
|
2014
|
+
if (eligibility.status === "disabled") return null;
|
|
2015
|
+
const { chatId, messageId, emoji, reactionOptions } = eligibility;
|
|
2073
2016
|
params.info({
|
|
2074
|
-
chatId
|
|
2075
|
-
messageId
|
|
2017
|
+
chatId,
|
|
2018
|
+
messageId,
|
|
2076
2019
|
emoji
|
|
2077
2020
|
}, "sending ack reaction");
|
|
2078
|
-
const sender = getSenderIdentity(params.msg);
|
|
2079
|
-
const reactionOptions = {
|
|
2080
|
-
verbose: params.verbose,
|
|
2081
|
-
fromMe: false,
|
|
2082
|
-
...sender.jid ? { participant: sender.jid } : {},
|
|
2083
|
-
accountId,
|
|
2084
|
-
cfg: params.cfg
|
|
2085
|
-
};
|
|
2086
2021
|
return createAckReactionHandle({
|
|
2087
2022
|
ackReactionValue: emoji,
|
|
2088
|
-
send: () => sendReactionWhatsApp(
|
|
2089
|
-
remove: () => sendReactionWhatsApp(
|
|
2023
|
+
send: () => sendReactionWhatsApp(chatId, messageId, emoji, reactionOptions),
|
|
2024
|
+
remove: () => sendReactionWhatsApp(chatId, messageId, "", reactionOptions),
|
|
2090
2025
|
onSendError: (err) => {
|
|
2091
2026
|
params.warn({
|
|
2092
2027
|
error: formatError(err),
|
|
2093
|
-
chatId
|
|
2094
|
-
messageId
|
|
2028
|
+
chatId,
|
|
2029
|
+
messageId
|
|
2095
2030
|
}, "failed to send ack reaction");
|
|
2096
|
-
logVerbose(`WhatsApp ack reaction failed for chat ${
|
|
2031
|
+
logVerbose(`WhatsApp ack reaction failed for chat ${chatId}: ${formatError(err)}`);
|
|
2097
2032
|
}
|
|
2098
2033
|
});
|
|
2099
2034
|
}
|
|
@@ -2249,7 +2184,13 @@ function recordPendingGroupHistoryEntry(params) {
|
|
|
2249
2184
|
body: params.body ?? params.msg.payload.body,
|
|
2250
2185
|
timestamp: params.msg.event.timestamp,
|
|
2251
2186
|
id: params.msg.event.id,
|
|
2252
|
-
senderJid: senderIdentity.jid ?? params.msg.platform.senderJid
|
|
2187
|
+
senderJid: senderIdentity.jid ?? params.msg.platform.senderJid,
|
|
2188
|
+
...params.body === void 0 && params.msg.payload.media ? { media: [{
|
|
2189
|
+
path: params.msg.payload.media.path,
|
|
2190
|
+
url: params.msg.payload.media.url ?? params.msg.payload.media.path,
|
|
2191
|
+
contentType: params.msg.payload.media.type,
|
|
2192
|
+
kind: params.msg.payload.media.kind ?? void 0
|
|
2193
|
+
}] } : {}
|
|
2253
2194
|
}
|
|
2254
2195
|
});
|
|
2255
2196
|
}
|
|
@@ -2585,7 +2526,7 @@ async function deliverWebReply(params) {
|
|
|
2585
2526
|
const tableMode = params.tableMode ?? "code";
|
|
2586
2527
|
const chunkMode = params.chunkMode ?? "length";
|
|
2587
2528
|
const normalizedReply = params.normalizedReplyResult ?? normalizeWhatsAppOutboundPayload(replyResult, { normalizeText: normalizeWhatsAppPayloadTextPreservingIndentation });
|
|
2588
|
-
const textChunks =
|
|
2529
|
+
const textChunks = markdownToWhatsAppChunks(normalizedReply.text ?? "", textLimit, tableMode, chunkMode);
|
|
2589
2530
|
const mediaList = normalizedReply.mediaUrls ?? [];
|
|
2590
2531
|
const getQuote = () => {
|
|
2591
2532
|
if (!replyResult.replyToId) return;
|
|
@@ -2595,7 +2536,8 @@ async function deliverWebReply(params) {
|
|
|
2595
2536
|
remoteJid: msg.platform.chatJid,
|
|
2596
2537
|
fromMe: cached?.fromMe ?? false,
|
|
2597
2538
|
participant: cached?.participant ?? (isGroupConversation ? msg.platform.senderJid : void 0),
|
|
2598
|
-
messageText: cached?.body ?? ""
|
|
2539
|
+
messageText: cached?.body ?? "",
|
|
2540
|
+
media: cached?.media
|
|
2599
2541
|
});
|
|
2600
2542
|
};
|
|
2601
2543
|
const sendWithRetry = async (fn, label) => {
|
|
@@ -2643,7 +2585,7 @@ async function deliverWebReply(params) {
|
|
|
2643
2585
|
mediaUrls: mediaList,
|
|
2644
2586
|
caption: remainingText.shift() || "",
|
|
2645
2587
|
send: async ({ mediaUrl, caption }) => {
|
|
2646
|
-
const media = await prepareWhatsAppOutboundMedia(await loadWebMedia
|
|
2588
|
+
const media = await prepareWhatsAppOutboundMedia(await loadWebMedia(mediaUrl, {
|
|
2647
2589
|
maxBytes: maxMediaBytes,
|
|
2648
2590
|
localRoots: params.mediaLocalRoots
|
|
2649
2591
|
}), mediaUrl);
|
|
@@ -2749,8 +2691,10 @@ function resolveVisibleWhatsAppGroupHistory(params) {
|
|
|
2749
2691
|
function resolveVisibleWhatsAppReplyContext(params) {
|
|
2750
2692
|
const replyTo = getReplyContext(params.msg, params.authDir);
|
|
2751
2693
|
if (!replyTo) return null;
|
|
2694
|
+
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
2695
|
+
const previewBody = [replyTo.body, formatMediaPlaceholderText(replyTo.media ? [replyTo.media] : [])].filter(Boolean).join("\n");
|
|
2752
2696
|
const senderAllowed = resolveInboundSupplementalSenderAllowed({
|
|
2753
|
-
isGroup:
|
|
2697
|
+
isGroup: admission.conversation.kind === "group",
|
|
2754
2698
|
groupPolicy: params.groupPolicy,
|
|
2755
2699
|
allowFrom: params.groupAllowFrom,
|
|
2756
2700
|
isSenderAllowed: (allowFrom) => isWhatsAppSupplementalSenderAllowed({
|
|
@@ -2759,12 +2703,16 @@ function resolveVisibleWhatsAppReplyContext(params) {
|
|
|
2759
2703
|
sender: replyTo.sender
|
|
2760
2704
|
})
|
|
2761
2705
|
});
|
|
2762
|
-
|
|
2706
|
+
const visible = filterChannelInboundQuoteContext(params.mode, {
|
|
2763
2707
|
id: replyTo.id,
|
|
2764
|
-
body:
|
|
2708
|
+
body: previewBody,
|
|
2765
2709
|
sender: replyTo.sender?.label ?? void 0,
|
|
2766
2710
|
senderAllowed
|
|
2767
|
-
})
|
|
2711
|
+
});
|
|
2712
|
+
return visible ? {
|
|
2713
|
+
...replyTo,
|
|
2714
|
+
body: visible.body ?? ""
|
|
2715
|
+
} : null;
|
|
2768
2716
|
}
|
|
2769
2717
|
//#endregion
|
|
2770
2718
|
//#region extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts
|
|
@@ -2780,14 +2728,16 @@ function normalizeErrForLog(err) {
|
|
|
2780
2728
|
function whatsAppReplyDeliveryVisibility(visibleReplySent) {
|
|
2781
2729
|
return { visibleReplySent };
|
|
2782
2730
|
}
|
|
2783
|
-
function
|
|
2784
|
-
return
|
|
2731
|
+
function isWhatsAppVisibleDeliveryError(error) {
|
|
2732
|
+
return typeof error === "object" && error !== null && !Array.isArray(error) && error.visibleReplySent === true || isChannelPartialDeliveryError(error) && error.deliveryResult.visibleReplySent;
|
|
2785
2733
|
}
|
|
2786
2734
|
function readTrimmedString(value) {
|
|
2787
2735
|
return typeof value === "string" ? value.trim() : "";
|
|
2788
2736
|
}
|
|
2789
2737
|
function markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult) {
|
|
2790
|
-
|
|
2738
|
+
if (flushResult.delivered === 0) return error;
|
|
2739
|
+
if (isWhatsAppVisibleDeliveryError(error)) return error;
|
|
2740
|
+
return markWhatsAppVisibleDeliveryError(new Error("deferred WhatsApp media delivery failed after an earlier visible send", { cause: error }));
|
|
2791
2741
|
}
|
|
2792
2742
|
function logWhatsAppReplyDeliveryError(params) {
|
|
2793
2743
|
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
@@ -2839,31 +2789,58 @@ function shouldDeferWhatsAppMediaOnlyPayload(params) {
|
|
|
2839
2789
|
}
|
|
2840
2790
|
function createWhatsAppMediaOnlyReplyCoalescer(params) {
|
|
2841
2791
|
const pendingMediaOnlyPayloads = [];
|
|
2842
|
-
const
|
|
2792
|
+
const flushWhere = async (shouldFlush) => {
|
|
2843
2793
|
const flushResult = {
|
|
2844
2794
|
delivered: 0,
|
|
2845
2795
|
droppedDuplicateMedia: 0
|
|
2846
2796
|
};
|
|
2847
|
-
const
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2797
|
+
const candidates = [];
|
|
2798
|
+
const retained = [];
|
|
2799
|
+
for (const pending of pendingMediaOnlyPayloads.splice(0)) if (shouldFlush(pending)) candidates.push(pending);
|
|
2800
|
+
else retained.push(pending);
|
|
2801
|
+
pendingMediaOnlyPayloads.push(...retained);
|
|
2802
|
+
for (const [index, candidate] of candidates.entries()) try {
|
|
2803
|
+
const delivery = await params.deliver(candidate);
|
|
2804
|
+
candidate.resolveFinalization(delivery);
|
|
2805
|
+
if (delivery.visibleReplySent) flushResult.delivered += 1;
|
|
2806
|
+
} catch (error) {
|
|
2807
|
+
const visibleError = markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult);
|
|
2808
|
+
candidate.rejectFinalization(error);
|
|
2809
|
+
for (const remaining of candidates.slice(index + 1)) remaining.rejectFinalization(new Error("deferred WhatsApp media delivery was not attempted", { cause: error }));
|
|
2810
|
+
throw visibleError;
|
|
2858
2811
|
}
|
|
2859
2812
|
return flushResult;
|
|
2860
2813
|
};
|
|
2861
2814
|
return {
|
|
2862
2815
|
defer(pending) {
|
|
2863
|
-
|
|
2816
|
+
let resolveFinalization;
|
|
2817
|
+
let rejectFinalization;
|
|
2818
|
+
const finalization = new Promise((resolve, reject) => {
|
|
2819
|
+
resolveFinalization = resolve;
|
|
2820
|
+
rejectFinalization = reject;
|
|
2821
|
+
});
|
|
2822
|
+
pendingMediaOnlyPayloads.push({
|
|
2823
|
+
...pending,
|
|
2824
|
+
resolveFinalization,
|
|
2825
|
+
rejectFinalization
|
|
2826
|
+
});
|
|
2827
|
+
return finalization;
|
|
2828
|
+
},
|
|
2829
|
+
flushNonDuplicateMedia: (mediaUrls) => flushWhere((pending) => !hasWhatsAppMediaUrlOverlap(pending.mediaUrls, mediaUrls)),
|
|
2830
|
+
dropDuplicateMedia(mediaUrls) {
|
|
2831
|
+
const flushResult = {
|
|
2832
|
+
delivered: 0,
|
|
2833
|
+
droppedDuplicateMedia: 0
|
|
2834
|
+
};
|
|
2835
|
+
const retained = [];
|
|
2836
|
+
for (const pending of pendingMediaOnlyPayloads.splice(0)) if (hasWhatsAppMediaUrlOverlap(pending.mediaUrls, mediaUrls)) {
|
|
2837
|
+
pending.resolveFinalization(whatsAppReplyDeliveryVisibility(false));
|
|
2838
|
+
flushResult.droppedDuplicateMedia += 1;
|
|
2839
|
+
} else retained.push(pending);
|
|
2840
|
+
pendingMediaOnlyPayloads.push(...retained);
|
|
2841
|
+
return flushResult;
|
|
2864
2842
|
},
|
|
2865
|
-
|
|
2866
|
-
flushAll: () => flushExceptDuplicateMedia()
|
|
2843
|
+
flushAll: () => flushWhere(() => true)
|
|
2867
2844
|
};
|
|
2868
2845
|
}
|
|
2869
2846
|
function logWhatsAppMediaOnlyFlushResult(result) {
|
|
@@ -2873,7 +2850,7 @@ function logWhatsAppMediaOnlyFlushResult(result) {
|
|
|
2873
2850
|
}
|
|
2874
2851
|
function resolveWhatsAppResponsePrefix(params) {
|
|
2875
2852
|
const configuredResponsePrefix = params.cfg.messages?.responsePrefix;
|
|
2876
|
-
return params.pipelineResponsePrefix ?? (configuredResponsePrefix ===
|
|
2853
|
+
return params.pipelineResponsePrefix ?? (configuredResponsePrefix === "auto" ? resolveIdentityNamePrefix$1(params.cfg, params.agentId) : configuredResponsePrefix) ?? (params.isSelfChat ? resolveIdentityNamePrefix$1(params.cfg, params.agentId) : void 0);
|
|
2877
2854
|
}
|
|
2878
2855
|
async function buildWhatsAppInboundContext(params) {
|
|
2879
2856
|
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
@@ -2885,14 +2862,16 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2885
2862
|
sender: entry.sender,
|
|
2886
2863
|
body: entry.body,
|
|
2887
2864
|
timestamp: entry.timestamp,
|
|
2888
|
-
messageId: entry.id
|
|
2865
|
+
messageId: entry.id,
|
|
2866
|
+
media: entry.media
|
|
2889
2867
|
})),
|
|
2890
2868
|
limit: params.groupHistory?.length ?? 1
|
|
2891
2869
|
}) : void 0;
|
|
2892
|
-
const media = toInboundMediaFacts(params.msg.payload.media
|
|
2870
|
+
const media = toInboundMediaFacts(params.msg.payload.media ? [{
|
|
2893
2871
|
path: params.msg.payload.media?.path,
|
|
2894
2872
|
url: params.msg.payload.media?.url ?? params.msg.payload.media?.path,
|
|
2895
|
-
contentType: params.msg.payload.media?.type
|
|
2873
|
+
contentType: params.msg.payload.media?.type,
|
|
2874
|
+
kind: params.msg.payload.media?.kind
|
|
2896
2875
|
}] : void 0, { transcribed: (_entry, index) => params.mediaTranscribedIndexes?.includes(index) === true });
|
|
2897
2876
|
return buildChannelInboundEventContext({
|
|
2898
2877
|
channel: "whatsapp",
|
|
@@ -2903,7 +2882,7 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2903
2882
|
sender: params.visibleReplyTo.sender?.label ?? void 0
|
|
2904
2883
|
} : void 0,
|
|
2905
2884
|
groupSystemPrompt: params.groupSystemPrompt,
|
|
2906
|
-
|
|
2885
|
+
channelStructuredContext: params.msg.payload.channelStructuredContext
|
|
2907
2886
|
},
|
|
2908
2887
|
media,
|
|
2909
2888
|
messageId: params.msg.event.id,
|
|
@@ -2935,6 +2914,7 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2935
2914
|
rawBody: params.rawBody ?? params.msg.payload.body,
|
|
2936
2915
|
commandBody: params.command?.body ?? params.msg.payload.body
|
|
2937
2916
|
},
|
|
2917
|
+
sessionTranscript: { historyLimit: conversationKind === "group" ? params.groupHistoryLimit ?? params.groupHistory?.length ?? 0 : 0 },
|
|
2938
2918
|
access: {
|
|
2939
2919
|
...wasMentioned !== void 0 ? { mentions: {
|
|
2940
2920
|
canDetectMention: conversationKind === "group",
|
|
@@ -2995,11 +2975,6 @@ function createWhatsAppReplyPlan(params) {
|
|
|
2995
2975
|
const conversationId = admission.conversation.id;
|
|
2996
2976
|
const conversationKind = admission.conversation.kind;
|
|
2997
2977
|
const statusReactionController = params.statusReactionController ?? null;
|
|
2998
|
-
const statusReactionTiming = {
|
|
2999
|
-
...DEFAULT_TIMING,
|
|
3000
|
-
...params.cfg.messages?.statusReactions?.timing
|
|
3001
|
-
};
|
|
3002
|
-
const removeAckAfterReply = params.cfg.messages?.removeAckAfterReply ?? false;
|
|
3003
2978
|
const textLimit = params.maxMediaTextChunkLimit ?? resolveTextChunkLimit(params.cfg, "whatsapp");
|
|
3004
2979
|
const chunkMode = resolveChunkMode(params.cfg, "whatsapp", params.route.accountId);
|
|
3005
2980
|
const tableMode = resolveMarkdownTableMode$1({
|
|
@@ -3016,7 +2991,20 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3016
2991
|
const disableBlockStreaming = sourceRepliesAreToolOnly ? true : resolveWhatsAppDisableBlockStreaming(params.cfg);
|
|
3017
2992
|
let didSendReply = false;
|
|
3018
2993
|
let didLogHeartbeatStrip = false;
|
|
3019
|
-
const
|
|
2994
|
+
const recordDeliveredPayload = (payload) => {
|
|
2995
|
+
didSendReply = true;
|
|
2996
|
+
const shouldLog = payload.text ? true : void 0;
|
|
2997
|
+
params.rememberSentText(payload.text, {
|
|
2998
|
+
combinedBody: params.context.Body,
|
|
2999
|
+
combinedBodySessionKey: params.route.sessionKey,
|
|
3000
|
+
logVerboseMessage: shouldLog
|
|
3001
|
+
});
|
|
3002
|
+
if (shouldLogVerbose$1()) {
|
|
3003
|
+
const reply = resolveSendableOutboundReplyParts(payload);
|
|
3004
|
+
logVerbose$1(`Reply body: ${payload.text != null ? reply.text : "<media>"}${reply.hasMedia ? " (media)" : ""} -> ${conversationId}`);
|
|
3005
|
+
}
|
|
3006
|
+
};
|
|
3007
|
+
const deliverNormalizedPayload = async (normalizedDeliveryPayload, info, options) => {
|
|
3020
3008
|
const reply = resolveSendableOutboundReplyParts(normalizedDeliveryPayload);
|
|
3021
3009
|
if (!reply.hasMedia && !reply.text.trim()) return whatsAppReplyDeliveryVisibility(false);
|
|
3022
3010
|
if (!(await params.deliverReply({
|
|
@@ -3043,15 +3031,11 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3043
3031
|
}, "auto-reply was not accepted by WhatsApp provider");
|
|
3044
3032
|
return whatsAppReplyDeliveryVisibility(false);
|
|
3045
3033
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
logVerboseMessage: shouldLog
|
|
3052
|
-
});
|
|
3053
|
-
const fromDisplay = conversationId;
|
|
3054
|
-
if (shouldLogVerbose$1()) logVerbose$1(`Reply body: ${normalizedDeliveryPayload.text != null ? reply.text : "<media>"}${reply.hasMedia ? " (media)" : ""} -> ${fromDisplay}`);
|
|
3034
|
+
if (options?.recordDelivery !== false) try {
|
|
3035
|
+
recordDeliveredPayload(normalizedDeliveryPayload);
|
|
3036
|
+
} catch (error) {
|
|
3037
|
+
throw markWhatsAppVisibleDeliveryError(error);
|
|
3038
|
+
}
|
|
3055
3039
|
return whatsAppReplyDeliveryVisibility(true);
|
|
3056
3040
|
};
|
|
3057
3041
|
const mediaOnlyCoalescer = createWhatsAppMediaOnlyReplyCoalescer({ deliver: async (pending) => {
|
|
@@ -3072,90 +3056,82 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3072
3056
|
onSettled: async () => {
|
|
3073
3057
|
const flushResult = await mediaOnlyCoalescer.flushAll();
|
|
3074
3058
|
logWhatsAppMediaOnlyFlushResult(flushResult);
|
|
3075
|
-
return whatsAppReplyDeliveryVisibility(flushResult.delivered > 0);
|
|
3059
|
+
return whatsAppReplyDeliveryVisibility(didSendReply || flushResult.delivered > 0);
|
|
3076
3060
|
},
|
|
3077
3061
|
onReplyStart: params.msg.platform.sendComposing
|
|
3078
3062
|
},
|
|
3079
3063
|
delivery: {
|
|
3080
|
-
|
|
3064
|
+
preparePayload: async (payload, info) => {
|
|
3081
3065
|
const deliveryPayload = resolveWhatsAppDeliverablePayload(payload, info);
|
|
3082
|
-
if (!deliveryPayload) return
|
|
3066
|
+
if (!deliveryPayload) return null;
|
|
3083
3067
|
const normalizedOutboundPayload = normalizeWhatsAppOutboundPayload(deliveryPayload, { normalizeText: normalizeWhatsAppPayloadTextPreservingIndentation });
|
|
3084
3068
|
const normalizedDeliveryPayload = deliveryPayload.text === void 0 ? {
|
|
3085
3069
|
...normalizedOutboundPayload,
|
|
3086
3070
|
text: void 0
|
|
3087
3071
|
} : normalizedOutboundPayload;
|
|
3088
3072
|
const reply = resolveSendableOutboundReplyParts(normalizedDeliveryPayload);
|
|
3089
|
-
if (!reply.hasMedia && !reply.text.trim()) return
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
if (durable.sentBeforeError === true) throw markWhatsAppVisibleDeliveryError(durable.error);
|
|
3117
|
-
throw durable.error;
|
|
3118
|
-
}
|
|
3119
|
-
if (durable.status === "handled_visible") {
|
|
3120
|
-
didSendReply = true;
|
|
3121
|
-
const shouldLog = normalizedDeliveryPayload.text ? true : void 0;
|
|
3122
|
-
params.rememberSentText(normalizedDeliveryPayload.text, {
|
|
3123
|
-
combinedBody: params.context.Body,
|
|
3124
|
-
combinedBodySessionKey: params.route.sessionKey,
|
|
3125
|
-
logVerboseMessage: shouldLog
|
|
3126
|
-
});
|
|
3127
|
-
return whatsAppReplyDeliveryVisibilityFromDurableResult(durable.delivery);
|
|
3128
|
-
}
|
|
3129
|
-
if (durable.status === "handled_no_send") return flushResult.delivered > 0 ? whatsAppReplyDeliveryVisibility(true) : whatsAppReplyDeliveryVisibilityFromDurableResult(durable.delivery);
|
|
3130
|
-
const deliveryResult = await deliverNormalizedPayload(normalizedDeliveryPayload, info);
|
|
3131
|
-
return flushResult.delivered > 0 && !deliveryResult.visibleReplySent ? whatsAppReplyDeliveryVisibility(true) : deliveryResult;
|
|
3132
|
-
} catch (error) {
|
|
3133
|
-
throw markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult);
|
|
3073
|
+
if (!reply.hasMedia && !reply.text.trim()) return normalizedDeliveryPayload;
|
|
3074
|
+
const mediaUrls = getWhatsAppPayloadMediaUrls(normalizedDeliveryPayload);
|
|
3075
|
+
logWhatsAppMediaOnlyFlushResult(reply.hasMedia ? shouldDeferWhatsAppMediaOnlyPayload({
|
|
3076
|
+
info,
|
|
3077
|
+
mediaUrls,
|
|
3078
|
+
reply
|
|
3079
|
+
}) ? {
|
|
3080
|
+
delivered: 0,
|
|
3081
|
+
droppedDuplicateMedia: 0
|
|
3082
|
+
} : await mediaOnlyCoalescer.flushNonDuplicateMedia(mediaUrls) : await mediaOnlyCoalescer.flushAll());
|
|
3083
|
+
return normalizedDeliveryPayload;
|
|
3084
|
+
},
|
|
3085
|
+
durable: (payload, info) => {
|
|
3086
|
+
const reply = resolveSendableOutboundReplyParts(payload);
|
|
3087
|
+
if (reply.hasMedia || !reply.text.trim()) return false;
|
|
3088
|
+
return {
|
|
3089
|
+
to: conversationId,
|
|
3090
|
+
replyToId: resolveWhatsAppDurableReplyToId({
|
|
3091
|
+
context: params.context,
|
|
3092
|
+
info,
|
|
3093
|
+
msg: params.msg,
|
|
3094
|
+
payload
|
|
3095
|
+
}),
|
|
3096
|
+
formatting: {
|
|
3097
|
+
textLimit,
|
|
3098
|
+
tableMode,
|
|
3099
|
+
chunkMode
|
|
3134
3100
|
}
|
|
3135
|
-
}
|
|
3101
|
+
};
|
|
3102
|
+
},
|
|
3103
|
+
deliver: async (payload, info) => {
|
|
3104
|
+
const normalizedDeliveryPayload = payload;
|
|
3105
|
+
const reply = resolveSendableOutboundReplyParts(normalizedDeliveryPayload);
|
|
3106
|
+
if (!reply.hasMedia && !reply.text.trim()) return whatsAppReplyDeliveryVisibility(false);
|
|
3107
|
+
if (!reply.hasMedia) return await deliverNormalizedPayload(normalizedDeliveryPayload, info, { recordDelivery: false });
|
|
3136
3108
|
const mediaUrls = getWhatsAppPayloadMediaUrls(normalizedDeliveryPayload);
|
|
3137
3109
|
if (shouldDeferWhatsAppMediaOnlyPayload({
|
|
3138
3110
|
info,
|
|
3139
3111
|
mediaUrls,
|
|
3140
3112
|
reply
|
|
3141
|
-
})) {
|
|
3142
|
-
|
|
3113
|
+
})) return {
|
|
3114
|
+
visibleReplySent: false,
|
|
3115
|
+
finalization: mediaOnlyCoalescer.defer({
|
|
3143
3116
|
info,
|
|
3144
3117
|
mediaUrls,
|
|
3145
3118
|
payload: normalizedDeliveryPayload
|
|
3146
|
-
})
|
|
3147
|
-
|
|
3148
|
-
}
|
|
3149
|
-
const flushResult = await mediaOnlyCoalescer.flushExceptDuplicateMedia(mediaUrls);
|
|
3150
|
-
logWhatsAppMediaOnlyFlushResult(flushResult);
|
|
3119
|
+
})
|
|
3120
|
+
};
|
|
3151
3121
|
try {
|
|
3152
|
-
const
|
|
3153
|
-
|
|
3122
|
+
const result = await deliverNormalizedPayload(normalizedDeliveryPayload, info);
|
|
3123
|
+
if (result.visibleReplySent) logWhatsAppMediaOnlyFlushResult(mediaOnlyCoalescer.dropDuplicateMedia(mediaUrls));
|
|
3124
|
+
return result;
|
|
3154
3125
|
} catch (error) {
|
|
3155
|
-
|
|
3126
|
+
if (isWhatsAppVisibleDeliveryError(error)) logWhatsAppMediaOnlyFlushResult(mediaOnlyCoalescer.dropDuplicateMedia(mediaUrls));
|
|
3127
|
+
throw error;
|
|
3156
3128
|
}
|
|
3157
3129
|
},
|
|
3130
|
+
onDelivered: (payload, _info, result) => {
|
|
3131
|
+
if (!resolveSendableOutboundReplyParts(payload).hasMedia && result?.visibleReplySent === true) recordDeliveredPayload(payload);
|
|
3132
|
+
},
|
|
3158
3133
|
onError: (err, info) => {
|
|
3134
|
+
if (didSendReply) markWhatsAppVisibleDeliveryError(err);
|
|
3159
3135
|
logWhatsAppReplyDeliveryError({
|
|
3160
3136
|
err,
|
|
3161
3137
|
info,
|
|
@@ -3189,13 +3165,10 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3189
3165
|
finalize: (dispatchResult) => {
|
|
3190
3166
|
const didQueueVisibleReply = hasVisibleInboundReplyDispatch(dispatchResult);
|
|
3191
3167
|
const didDeliverVisibleReply = didSendReply || dispatchResult.observedReplyDelivery === true;
|
|
3192
|
-
if (!didQueueVisibleReply) {
|
|
3168
|
+
if (!didQueueVisibleReply && !didDeliverVisibleReply) {
|
|
3193
3169
|
if (statusReactionController) finalizeWhatsAppStatusReaction({
|
|
3194
3170
|
controller: statusReactionController,
|
|
3195
|
-
outcome: "error"
|
|
3196
|
-
hasFinalResponse: false,
|
|
3197
|
-
removeAckAfterReply,
|
|
3198
|
-
timing: statusReactionTiming
|
|
3171
|
+
outcome: "error"
|
|
3199
3172
|
});
|
|
3200
3173
|
if (params.shouldClearGroupHistory) params.groupHistories.set(params.groupHistoryKey, []);
|
|
3201
3174
|
logVerbose$1("Skipping auto-reply: silent token or no text/media returned from resolver");
|
|
@@ -3203,10 +3176,7 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3203
3176
|
}
|
|
3204
3177
|
if (statusReactionController) finalizeWhatsAppStatusReaction({
|
|
3205
3178
|
controller: statusReactionController,
|
|
3206
|
-
outcome: didDeliverVisibleReply ? "done" : "error"
|
|
3207
|
-
hasFinalResponse: didDeliverVisibleReply,
|
|
3208
|
-
removeAckAfterReply,
|
|
3209
|
-
timing: statusReactionTiming
|
|
3179
|
+
outcome: didDeliverVisibleReply ? "done" : "error"
|
|
3210
3180
|
});
|
|
3211
3181
|
if (params.shouldClearGroupHistory) params.groupHistories.set(params.groupHistoryKey, []);
|
|
3212
3182
|
return didDeliverVisibleReply;
|
|
@@ -3214,29 +3184,8 @@ function createWhatsAppReplyPlan(params) {
|
|
|
3214
3184
|
};
|
|
3215
3185
|
}
|
|
3216
3186
|
async function finalizeWhatsAppStatusReaction(params) {
|
|
3217
|
-
if (params.outcome === "done")
|
|
3218
|
-
|
|
3219
|
-
if (params.removeAckAfterReply) {
|
|
3220
|
-
await new Promise((resolve) => {
|
|
3221
|
-
setTimeout(resolve, params.timing.doneHoldMs);
|
|
3222
|
-
});
|
|
3223
|
-
await params.controller.clear();
|
|
3224
|
-
} else await params.controller.restoreInitial();
|
|
3225
|
-
return;
|
|
3226
|
-
}
|
|
3227
|
-
await params.controller.setError();
|
|
3228
|
-
if (params.hasFinalResponse) {
|
|
3229
|
-
if (params.removeAckAfterReply) {
|
|
3230
|
-
await new Promise((resolve) => {
|
|
3231
|
-
setTimeout(resolve, params.timing.errorHoldMs);
|
|
3232
|
-
});
|
|
3233
|
-
await params.controller.clear();
|
|
3234
|
-
} else await params.controller.restoreInitial();
|
|
3235
|
-
return;
|
|
3236
|
-
}
|
|
3237
|
-
if (params.removeAckAfterReply) await new Promise((resolve) => {
|
|
3238
|
-
setTimeout(resolve, params.timing.errorHoldMs);
|
|
3239
|
-
});
|
|
3187
|
+
if (params.outcome === "done") await params.controller.setDone();
|
|
3188
|
+
else await params.controller.setError();
|
|
3240
3189
|
await params.controller.restoreInitial();
|
|
3241
3190
|
}
|
|
3242
3191
|
//#endregion
|
|
@@ -3250,7 +3199,7 @@ function resolveIdentityNamePrefix(cfg, agentId) {
|
|
|
3250
3199
|
return identityName ? `[${identityName}]` : void 0;
|
|
3251
3200
|
}
|
|
3252
3201
|
function resolveMessagePrefix(cfg, agentId, opts) {
|
|
3253
|
-
const configured = opts?.configured
|
|
3202
|
+
const configured = opts?.configured;
|
|
3254
3203
|
if (configured !== void 0) return configured;
|
|
3255
3204
|
if (opts?.hasAllowFrom === true) return "";
|
|
3256
3205
|
return resolveIdentityNamePrefix(cfg, agentId) ?? opts?.fallback ?? "[openclaw]";
|
|
@@ -3267,7 +3216,7 @@ function formatReplyContext(msg) {
|
|
|
3267
3216
|
function buildInboundLine(params) {
|
|
3268
3217
|
const { cfg, msg, agentId, previousTimestamp, envelope } = params;
|
|
3269
3218
|
const messagePrefix = resolveMessagePrefix(cfg, agentId, {
|
|
3270
|
-
configured: cfg.channels?.whatsapp?.
|
|
3219
|
+
configured: cfg.channels?.whatsapp?.responsePrefix,
|
|
3271
3220
|
hasAllowFrom: (cfg.channels?.whatsapp?.allowFrom?.length ?? 0) > 0
|
|
3272
3221
|
});
|
|
3273
3222
|
const admission = requireWhatsAppInboundAdmission(msg);
|
|
@@ -3297,66 +3246,30 @@ function buildInboundLine(params) {
|
|
|
3297
3246
|
//#region extensions/whatsapp/src/auto-reply/monitor/status-reaction.ts
|
|
3298
3247
|
async function createWhatsAppStatusReactionController(params) {
|
|
3299
3248
|
if (!params.msg.event.id) return null;
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
3303
|
-
const accountId = admission.accountId;
|
|
3304
|
-
if (resolveWhatsAppReactionLevel({
|
|
3305
|
-
cfg: params.cfg,
|
|
3306
|
-
accountId
|
|
3307
|
-
}).level === "off") return null;
|
|
3308
|
-
const ackConfig = params.cfg.channels?.whatsapp?.ackReaction;
|
|
3309
|
-
const ackEmoji = resolveWhatsAppAckEmoji({
|
|
3310
|
-
cfg: params.cfg,
|
|
3311
|
-
agentId: params.agentId,
|
|
3312
|
-
ackConfig
|
|
3313
|
-
});
|
|
3314
|
-
if (!ackEmoji) return null;
|
|
3315
|
-
const directEnabled = ackConfig?.direct ?? true;
|
|
3316
|
-
const groupMode = ackConfig?.group ?? "mentions";
|
|
3317
|
-
const isGroup = admission.conversation.kind === "group";
|
|
3318
|
-
const conversationIdForCheck = admission.conversation.id;
|
|
3319
|
-
const activation = isGroup ? await resolveGroupActivationFor({
|
|
3249
|
+
if ((params.cfg.messages?.statusReactions)?.enabled !== true) return null;
|
|
3250
|
+
const eligibility = await resolveWhatsAppReactionEligibility({
|
|
3320
3251
|
cfg: params.cfg,
|
|
3321
|
-
|
|
3252
|
+
msg: params.msg,
|
|
3322
3253
|
agentId: params.agentId,
|
|
3323
3254
|
sessionKey: params.sessionKey,
|
|
3324
|
-
|
|
3325
|
-
})
|
|
3326
|
-
if (
|
|
3327
|
-
|
|
3328
|
-
isDirect: admission.conversation.kind === "direct",
|
|
3329
|
-
isGroup,
|
|
3330
|
-
directEnabled,
|
|
3331
|
-
groupMode,
|
|
3332
|
-
wasMentioned: (params.msg.groupMention?.wasMentioned ?? params.msg.wasMentioned) === true,
|
|
3333
|
-
groupActivated: activation === "always"
|
|
3334
|
-
})) return null;
|
|
3335
|
-
const sender = getSenderIdentity(params.msg);
|
|
3336
|
-
const reactionOptions = {
|
|
3337
|
-
verbose: params.verbose,
|
|
3338
|
-
fromMe: false,
|
|
3339
|
-
...sender.jid ? { participant: sender.jid } : {},
|
|
3340
|
-
accountId,
|
|
3341
|
-
cfg: params.cfg
|
|
3342
|
-
};
|
|
3343
|
-
const chatId = params.msg.platform.chatJid;
|
|
3344
|
-
const msgId = params.msg.event.id;
|
|
3255
|
+
verbose: params.verbose
|
|
3256
|
+
});
|
|
3257
|
+
if (eligibility.status === "disabled") return null;
|
|
3258
|
+
const { chatId, messageId, emoji: initialEmoji, reactionOptions } = eligibility;
|
|
3345
3259
|
return createStatusReactionController({
|
|
3346
3260
|
enabled: true,
|
|
3347
3261
|
adapter: {
|
|
3348
3262
|
setReaction: async (emoji) => {
|
|
3349
|
-
await sendReactionWhatsApp(chatId,
|
|
3263
|
+
await sendReactionWhatsApp(chatId, messageId, emoji, reactionOptions);
|
|
3350
3264
|
},
|
|
3351
3265
|
clearReaction: async () => {
|
|
3352
|
-
await sendReactionWhatsApp(chatId,
|
|
3266
|
+
await sendReactionWhatsApp(chatId, messageId, "", reactionOptions);
|
|
3353
3267
|
}
|
|
3354
3268
|
},
|
|
3355
|
-
initialEmoji
|
|
3356
|
-
emojis:
|
|
3357
|
-
timing: statusReactionsConfig.timing,
|
|
3269
|
+
initialEmoji,
|
|
3270
|
+
emojis: void 0,
|
|
3358
3271
|
onError: (err) => {
|
|
3359
|
-
logVerbose(`WhatsApp status-reaction error for chat ${chatId}/${
|
|
3272
|
+
logVerbose(`WhatsApp status-reaction error for chat ${chatId}/${messageId}: ${String(err)}`);
|
|
3360
3273
|
}
|
|
3361
3274
|
});
|
|
3362
3275
|
}
|
|
@@ -3423,13 +3336,16 @@ async function processMessage(params) {
|
|
|
3423
3336
|
sessionKey: params.route.sessionKey
|
|
3424
3337
|
});
|
|
3425
3338
|
let audioTranscript = params.preflightAudioTranscript ?? void 0;
|
|
3426
|
-
const hasAudioBody = params.msg.payload.media?.type?.startsWith("audio/") === true && params.msg.payload.body
|
|
3339
|
+
const hasAudioBody = (params.msg.payload.media?.kind === "audio" || params.msg.payload.media?.type?.startsWith("audio/") === true) && !params.msg.payload.body.trim();
|
|
3427
3340
|
if (params.preflightAudioTranscript === void 0 && hasAudioBody && params.msg.payload.media?.path) try {
|
|
3428
3341
|
const { transcribeFirstAudio } = await import("./audio-preflight.runtime-C_glQhZY.js");
|
|
3429
3342
|
audioTranscript = await transcribeFirstAudio({
|
|
3430
3343
|
ctx: {
|
|
3431
|
-
|
|
3432
|
-
|
|
3344
|
+
media: [{
|
|
3345
|
+
path: params.msg.payload.media.path,
|
|
3346
|
+
contentType: params.msg.payload.media.type,
|
|
3347
|
+
kind: params.msg.payload.media.kind ?? void 0
|
|
3348
|
+
}],
|
|
3433
3349
|
From: conversationId,
|
|
3434
3350
|
To: params.msg.platform.recipientJid,
|
|
3435
3351
|
Provider: "whatsapp",
|
|
@@ -3441,7 +3357,7 @@ async function processMessage(params) {
|
|
|
3441
3357
|
cfg: params.cfg
|
|
3442
3358
|
});
|
|
3443
3359
|
} catch {
|
|
3444
|
-
if (shouldLogVerbose$1()) logVerbose$1("whatsapp: audio preflight transcription failed,
|
|
3360
|
+
if (shouldLogVerbose$1()) logVerbose$1("whatsapp: audio preflight transcription failed, keeping structured audio");
|
|
3445
3361
|
}
|
|
3446
3362
|
const msgForAgent = audioTranscript !== void 0 ? {
|
|
3447
3363
|
...params.msg,
|
|
@@ -3479,7 +3395,8 @@ async function processMessage(params) {
|
|
|
3479
3395
|
entries: history.map((m) => ({
|
|
3480
3396
|
sender: m.sender,
|
|
3481
3397
|
body: m.body,
|
|
3482
|
-
timestamp: m.timestamp
|
|
3398
|
+
timestamp: m.timestamp,
|
|
3399
|
+
media: m.media
|
|
3483
3400
|
})),
|
|
3484
3401
|
currentMessage: combinedBody,
|
|
3485
3402
|
excludeLast: false,
|
|
@@ -3488,7 +3405,7 @@ async function processMessage(params) {
|
|
|
3488
3405
|
channel: "WhatsApp",
|
|
3489
3406
|
from: conversationId,
|
|
3490
3407
|
timestamp: entry.timestamp,
|
|
3491
|
-
body: entry.body,
|
|
3408
|
+
body: [entry.body, formatMediaPlaceholderText(entry.media ?? [])].filter(Boolean).join("\n"),
|
|
3492
3409
|
chatType: "group",
|
|
3493
3410
|
senderLabel: entry.sender,
|
|
3494
3411
|
envelope: envelopeOptions
|
|
@@ -3582,6 +3499,7 @@ async function processMessage(params) {
|
|
|
3582
3499
|
authorized: commandAuthorized
|
|
3583
3500
|
},
|
|
3584
3501
|
groupHistory: visibleGroupHistory,
|
|
3502
|
+
groupHistoryLimit: params.groupHistoryLimit,
|
|
3585
3503
|
groupMemberRoster: params.groupMemberNames.get(params.groupHistoryKey),
|
|
3586
3504
|
groupSystemPrompt: conversationSystemPrompt,
|
|
3587
3505
|
msg: params.msg,
|
|
@@ -3704,7 +3622,7 @@ async function processMessage(params) {
|
|
|
3704
3622
|
});
|
|
3705
3623
|
const didSendReply = turnResult.dispatched ? finalizeReply?.(turnResult.dispatchResult) ?? false : false;
|
|
3706
3624
|
removeAckReactionHandleAfterReply({
|
|
3707
|
-
removeAfterReply:
|
|
3625
|
+
removeAfterReply: false,
|
|
3708
3626
|
ackReaction,
|
|
3709
3627
|
onError: (err) => {
|
|
3710
3628
|
logAckFailure({
|
|
@@ -3744,6 +3662,7 @@ function createWebOnMessageHandler(params) {
|
|
|
3744
3662
|
route,
|
|
3745
3663
|
groupHistoryKey,
|
|
3746
3664
|
groupHistories: params.groupHistories,
|
|
3665
|
+
groupHistoryLimit: params.groupHistoryLimit,
|
|
3747
3666
|
groupMemberNames: params.groupMemberNames,
|
|
3748
3667
|
connectionId: params.connectionId,
|
|
3749
3668
|
verbose: params.verbose,
|
|
@@ -3811,7 +3730,7 @@ function createWebOnMessageHandler(params) {
|
|
|
3811
3730
|
peerId
|
|
3812
3731
|
}) : route.sessionKey;
|
|
3813
3732
|
let preflightAudioTranscript;
|
|
3814
|
-
const hasAudioBody = msg.payload.media?.type?.startsWith("audio/") === true && msg.payload.body
|
|
3733
|
+
const hasAudioBody = (msg.payload.media?.kind === "audio" || msg.payload.media?.type?.startsWith("audio/") === true) && !msg.payload.body.trim();
|
|
3815
3734
|
const canRunEarlyAudioPreflight = conversationKind === "group" || canRunDirectEarlyAudioPreflight;
|
|
3816
3735
|
let ackAlreadySent = false;
|
|
3817
3736
|
let ackReaction = null;
|
|
@@ -3837,8 +3756,11 @@ function createWebOnMessageHandler(params) {
|
|
|
3837
3756
|
const { transcribeFirstAudio } = await import("./audio-preflight.runtime-C_glQhZY.js");
|
|
3838
3757
|
preflightAudioTranscript = await transcribeFirstAudio({
|
|
3839
3758
|
ctx: {
|
|
3840
|
-
|
|
3841
|
-
|
|
3759
|
+
media: [{
|
|
3760
|
+
path: msg.payload.media.path,
|
|
3761
|
+
contentType: msg.payload.media.type,
|
|
3762
|
+
kind: msg.payload.media.kind ?? void 0
|
|
3763
|
+
}],
|
|
3842
3764
|
From: conversationId,
|
|
3843
3765
|
To: msg.platform.recipientJid,
|
|
3844
3766
|
Provider: "whatsapp",
|
|
@@ -4009,8 +3931,7 @@ function resolveWebMonitorConfigSnapshot(params) {
|
|
|
4009
3931
|
...params.cfg.channels,
|
|
4010
3932
|
whatsapp: {
|
|
4011
3933
|
...params.cfg.channels?.whatsapp,
|
|
4012
|
-
|
|
4013
|
-
messagePrefix: account.messagePrefix,
|
|
3934
|
+
responsePrefix: account.messagePrefix,
|
|
4014
3935
|
allowFrom: account.allowFrom,
|
|
4015
3936
|
groupAllowFrom: account.groupAllowFrom,
|
|
4016
3937
|
groupPolicy: account.groupPolicy,
|
|
@@ -4024,23 +3945,11 @@ function resolveWebMonitorConfigSnapshot(params) {
|
|
|
4024
3945
|
account
|
|
4025
3946
|
};
|
|
4026
3947
|
}
|
|
4027
|
-
function normalizeReconnectAccountId(accountId) {
|
|
4028
|
-
return (accountId ?? "").trim() || "default";
|
|
4029
|
-
}
|
|
4030
3948
|
function isNoListenerReconnectError(lastError) {
|
|
4031
3949
|
return typeof lastError === "string" && /No active WhatsApp Web listener/i.test(lastError);
|
|
4032
3950
|
}
|
|
4033
|
-
function
|
|
4034
|
-
|
|
4035
|
-
if (!channel) return;
|
|
4036
|
-
const accountId = normalizeReconnectAccountId(params.accountId);
|
|
4037
|
-
const accountDebounce = resolveAccountEntry(channel.accounts, accountId)?.debounceMs;
|
|
4038
|
-
if (accountDebounce !== void 0) return accountDebounce;
|
|
4039
|
-
if (accountId !== "default") {
|
|
4040
|
-
const defaultAccountDebounce = resolveAccountEntry(channel.accounts, "default")?.debounceMs;
|
|
4041
|
-
if (defaultAccountDebounce !== void 0) return defaultAccountDebounce;
|
|
4042
|
-
}
|
|
4043
|
-
return channel.debounceMs;
|
|
3951
|
+
function normalizeReconnectAccountId(accountId) {
|
|
3952
|
+
return (accountId ?? "").trim() || "default";
|
|
4044
3953
|
}
|
|
4045
3954
|
function isRetryableAuthUnstableError(error) {
|
|
4046
3955
|
return error instanceof WhatsAppAuthUnstableError || typeof error === "object" && error !== null && "code" in error && error.code === "whatsapp-auth-unstable";
|
|
@@ -4062,10 +3971,8 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
4062
3971
|
module: "web-reconnect",
|
|
4063
3972
|
runId
|
|
4064
3973
|
});
|
|
4065
|
-
const baseCfg = getRuntimeConfig$1();
|
|
4066
|
-
const sourceCfg = getRuntimeConfigSourceSnapshot();
|
|
4067
3974
|
const { cfg, account } = resolveWebMonitorConfigSnapshot({
|
|
4068
|
-
cfg:
|
|
3975
|
+
cfg: getRuntimeConfig$1(),
|
|
4069
3976
|
accountId: tuning.accountId
|
|
4070
3977
|
});
|
|
4071
3978
|
const loadCurrentMonitorConfig = () => resolveWebMonitorConfigSnapshot({
|
|
@@ -4075,7 +3982,7 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
4075
3982
|
const maxMediaBytes = resolveWhatsAppMediaMaxBytes(account);
|
|
4076
3983
|
const heartbeatSeconds = resolveHeartbeatSeconds(cfg, tuning.heartbeatSeconds);
|
|
4077
3984
|
const reconnectPolicy = resolveReconnectPolicy(cfg, tuning.reconnect);
|
|
4078
|
-
const socketTiming = resolveWhatsAppSocketTiming(
|
|
3985
|
+
const socketTiming = resolveWhatsAppSocketTiming(tuning.socketTiming);
|
|
4079
3986
|
const baseMentionConfig = buildMentionConfig(cfg);
|
|
4080
3987
|
const groupHistoryLimit = account.historyLimit ?? cfg.channels?.whatsapp?.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT;
|
|
4081
3988
|
const groupHistories = /* @__PURE__ */ new Map();
|
|
@@ -4123,12 +4030,7 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
4123
4030
|
const connectionId = newConnectionId();
|
|
4124
4031
|
const inboundDebounceMs = resolveInboundDebounceMs({
|
|
4125
4032
|
cfg,
|
|
4126
|
-
channel: "whatsapp"
|
|
4127
|
-
overrideMs: resolveExplicitWhatsAppDebounceOverride({
|
|
4128
|
-
cfg,
|
|
4129
|
-
sourceCfg,
|
|
4130
|
-
accountId: account.accountId
|
|
4131
|
-
})
|
|
4033
|
+
channel: "whatsapp"
|
|
4132
4034
|
});
|
|
4133
4035
|
const shouldDebounce = (msg) => {
|
|
4134
4036
|
const normalized = normalizeWebInboundMessage(msg);
|
|
@@ -4474,4 +4376,4 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
4474
4376
|
}
|
|
4475
4377
|
}
|
|
4476
4378
|
//#endregion
|
|
4477
|
-
export { loadWebMediaRaw as a, monitorWebInbox as c, loadWebMedia
|
|
4379
|
+
export { loadWebMediaRaw as a, monitorWebInbox as c, loadWebMedia as i, resetWebInboundDedupe as l, LocalMediaAccessError as n, optimizeImageToJpeg as o, getDefaultLocalRoots as r, optimizeImageToPng as s, monitorWebChannel as t };
|