@openclaw/whatsapp 2026.7.1 → 2026.7.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{access-control-DYE5dXna.js → access-control-DazDX3RB.js} +4 -4
- package/dist/{account-config-6PTOSfaI.js → account-config-LiT9wWH9.js} +4 -8
- package/dist/{accounts-4YgwroRU.js → accounts-CKOFMPf-.js} +2 -3
- package/dist/{action-runtime-DPahAqxV.js → action-runtime-Bf-12TIH.js} +3 -3
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/{active-listener-B4SDebQ6.js → active-listener-5kHap439.js} +2 -2
- package/dist/{agent-tools-login-BX7eHgDm.js → agent-tools-login-DfyToBpG.js} +1 -4
- package/dist/api.js +17 -18
- package/dist/{approval-handler.runtime-DNWS4aYQ.js → approval-handler.runtime-CBiGQuZ5.js} +19 -13
- package/dist/approval-reactions-BGQoz25s.js +373 -0
- package/dist/{approval-resolver-DF-lu8k5.js → approval-resolver-DoeBBt22.js} +2 -1
- package/dist/{auth-store-Db-wfApd.js → auth-store-BQi9pZqQ.js} +31 -19
- package/dist/call-tool-api.js +6 -14
- package/dist/{channel-BWp7h1uY.js → channel-DbadDUDD.js} +84 -52
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-CKJHL_Wf.js → channel-react-action-PoRWfP9x.js} +7 -7
- package/dist/{channel.runtime-CAssfx9p.js → channel.runtime-BDDy4Lhz.js} +5 -5
- package/dist/{channel.setup-CURc5rEt.js → channel.setup-BZ-po8fg.js} +4 -5
- package/dist/config-schema-BZ8h1hWA.js +40 -0
- package/dist/{connection-controller-DkbrFSIn.js → connection-controller-C1rwfWb4.js} +52 -12
- package/dist/connection-controller-runtime-context-CbTsqmPT.js +14 -0
- package/dist/contract-api.js +2 -2
- package/dist/{directory-config-Dijefxc3.js → directory-config-CLBQrjtC.js} +3 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +89 -4
- package/dist/{group-session-key-BhC1RQOE.js → group-session-key-CLTZeH_F.js} +31 -3
- package/dist/{identity-Dqft3mFA.js → identity-D7L8LCuH.js} +2 -2
- package/dist/legacy-state-migrations-api.js +1 -1
- package/dist/light-runtime-api.js +4 -4
- package/dist/{login-C48y0jlx.js → login-DGIoToX8.js} +48 -8
- package/dist/{login-qr-BjId7dll.js → login-qr-X-CZHOk9.js} +6 -7
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-DD8bXohk.js → monitor-BZ8QvCeV.js} +145 -188
- package/dist/normalize-C-Z16y7Q.js +2 -0
- package/dist/{normalize-target-bVWjgftN.js → normalize-target-DSZnHkKF.js} +14 -10
- package/dist/{resolve-outbound-target-CcdugbDf.js → resolve-outbound-target-BR97fAbB.js} +1 -1
- package/dist/runtime-api.js +10 -10
- package/dist/{send-C5CpFcBG.js → send-D9Ydnn4o.js} +25 -320
- package/dist/{send-api-DLlXl8CH.js → send-api-W33lI2nR.js} +28 -88
- package/dist/{session-errors-BAj9D2La.js → session-errors-JuazczrA.js} +2 -1
- package/dist/{session-DriaHt7V.js → session-mxWFn0eS.js} +181 -19
- package/dist/session.runtime-Nsqaehbd.js +16 -0
- package/dist/{setup-core-DH-DFPLY.js → setup-core-3aSOoK2T.js} +18 -33
- package/dist/{setup-finalize-c8dl34sO.js → setup-finalize-DBf1jjBj.js} +41 -11
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-DlWb0Z09.js → setup-surface-CiKGdNJv.js} +3 -3
- package/dist/{state-migrations-D_BmQUR9.js → state-migrations-CAMTrs2U.js} +1 -8
- package/dist/{targets-runtime-C-GiVn6Y.js → targets-runtime-Bsh0HR9y.js} +13 -6
- package/dist/text-runtime-BTGkMN0o.js +4 -0
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +72 -48
- package/package.json +4 -4
- package/dist/config-schema-mBX2nmn1.js +0 -47
- package/dist/connection-controller-registry-TSX_udJp.js +0 -22
- package/dist/constants.js +0 -2
- package/dist/normalize-Bxwqo-bW.js +0 -2
- package/dist/session.runtime-CyooSQvj.js +0 -12
- package/dist/socket-timing-DhbVFjah.js +0 -77
- package/dist/targets.js +0 -2
- package/dist/text-runtime-DdX6-mC_.js +0 -4
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-
|
|
2
|
-
import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia,
|
|
1
|
+
import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CKOFMPf-.js";
|
|
2
|
+
import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation, u as resolveWhatsAppReactionLevel } from "./send-D9Ydnn4o.js";
|
|
3
3
|
import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
|
|
4
|
-
import {
|
|
5
|
-
import { n as
|
|
6
|
-
import {
|
|
7
|
-
import { a as
|
|
8
|
-
import {
|
|
9
|
-
import { a as
|
|
10
|
-
import { g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-Db-wfApd.js";
|
|
11
|
-
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-Dqft3mFA.js";
|
|
4
|
+
import { n as getWhatsAppConnectionController } from "./connection-controller-runtime-context-CbTsqmPT.js";
|
|
5
|
+
import { a as resolveEquivalentWhatsAppDirectChatJids, c as toWhatsappJidWithLid, i as markdownToWhatsApp, n as isSelfChatMode, o as resolveJidToE164, r as jidToE164, s as toWhatsappJid } from "./targets-runtime-Bsh0HR9y.js";
|
|
6
|
+
import { n as normalizeE164, t as convertMarkdownTables$1 } from "./text-runtime-BTGkMN0o.js";
|
|
7
|
+
import { a as cacheInboundMessageMeta, i as buildQuotedMessageOptions, n as resolveWhatsAppGroupSessionRoute, o as lookupInboundMessageMeta, r as resolveWhatsAppLegacyGroupSessionKey } from "./group-session-key-CLTZeH_F.js";
|
|
8
|
+
import { g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-BQi9pZqQ.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-D7L8LCuH.js";
|
|
12
10
|
import { n as resolveWhatsAppGroupsConfigPath } from "./group-config-path-BGyzT9Lg.js";
|
|
13
|
-
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-
|
|
14
|
-
import { _ as extractLocationData, a as mayContainWhatsAppOutboundMention, b as extractText, c as DisconnectReason, d as normalizeMessageContent, f as resolveInboundMediaMimetype, g as extractExternalAdReplyContext, h as extractContextInfo, i as addWhatsAppOutboundMentionsToContent, l as downloadMediaMessage, m as extractContactContext, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as describeReplyContext, r as normalizeWhatsAppSendResult, s as addWhatsAppImagePreviewFields, t as createWebSendApi, u as isJidGroup, v as extractMediaPlaceholder, x as hasInboundUserContent, y as extractMentionedJids } from "./send-api-
|
|
15
|
-
import { r as waitForWaConnection, t as createWaSocket } from "./session-
|
|
16
|
-
import { t as
|
|
17
|
-
import {
|
|
11
|
+
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-DazDX3RB.js";
|
|
12
|
+
import { _ as extractLocationData, a as mayContainWhatsAppOutboundMention, b as extractText, c as DisconnectReason, d as normalizeMessageContent, f as resolveInboundMediaMimetype, g as extractExternalAdReplyContext, h as extractContextInfo, i as addWhatsAppOutboundMentionsToContent, l as downloadMediaMessage, m as extractContactContext, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as describeReplyContext, r as normalizeWhatsAppSendResult, s as addWhatsAppImagePreviewFields, t as createWebSendApi, u as isJidGroup, v as extractMediaPlaceholder, x as hasInboundUserContent, y as extractMentionedJids } from "./send-api-W33lI2nR.js";
|
|
13
|
+
import { a as createWhatsAppSocketOperationTimeoutAdapter, c as resolveWhatsAppSocketTiming, l as withWhatsAppSocketOperationTimeout, o as isWhatsAppSocketOperationTimeoutError, r as waitForWaConnection, s as resolveWhatsAppSocketOperationTimeoutMs, t as createWaSocket } from "./session-mxWFn0eS.js";
|
|
14
|
+
import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
|
|
15
|
+
import { t as BufferJSON } from "./session.runtime-Nsqaehbd.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-C1rwfWb4.js";
|
|
17
|
+
import { n as maybeResolveWhatsAppApprovalReaction } from "./approval-reactions-BGQoz25s.js";
|
|
18
18
|
import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
|
|
19
|
-
import { normalizeLowercaseStringOrEmpty, normalizeStringEntries
|
|
20
|
-
import { createChannelMessageReplyPipeline, createDurableInboundReceiveJournalFromQueue, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode } from "openclaw/plugin-sdk/channel-outbound";
|
|
19
|
+
import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
21
20
|
import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
22
21
|
import { DEFAULT_TIMING, createAckReactionHandle, createStatusReactionController, logAckFailure, removeAckReactionHandleAfterReply, shouldAckReactionForWhatsApp } from "openclaw/plugin-sdk/channel-feedback";
|
|
23
22
|
import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
|
|
23
|
+
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
24
24
|
import { getChildLogger } from "openclaw/plugin-sdk/logging-core";
|
|
25
25
|
import { resolveMarkdownTableMode as resolveMarkdownTableMode$1 } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
26
26
|
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
|
-
import {
|
|
27
|
+
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
28
|
+
import { createChannelMessageReplyPipeline, createDurableInboundReceiveJournalFromQueue, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
28
29
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
|
|
29
|
-
import {
|
|
30
|
+
import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
|
|
30
31
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
31
32
|
import { LocalMediaAccessError, getDefaultLocalRoots, loadWebMedia as loadWebMedia$1, loadWebMediaRaw, optimizeImageToJpeg, optimizeImageToPng } from "openclaw/plugin-sdk/web-media";
|
|
33
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
32
34
|
import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
|
|
33
|
-
import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
|
|
34
35
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId as normalizeAccountId$1, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
36
|
+
import { asDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
35
37
|
import { recordInboundSession } from "openclaw/plugin-sdk/conversation-runtime";
|
|
36
38
|
import { getSessionEntry, patchSessionEntry, resolveStorePath, resolveStorePath as resolveStorePath$1, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
|
|
37
|
-
import { buildChannelInboundEventContext, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundEnvelope as formatInboundEnvelope$1, formatInboundMediaUnavailableText, formatLocationText, hasVisibleInboundReplyDispatch, resolveInboundSessionEnvelopeContext, runChannelInboundEvent, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
38
|
-
import { saveMediaStream } from "openclaw/plugin-sdk/media-store";
|
|
39
|
+
import { buildChannelInboundEventContext, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundEnvelope as formatInboundEnvelope$1, formatInboundMediaUnavailableText, formatLocationText, hasVisibleInboundReplyDispatch, resolveInboundSessionEnvelopeContext, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
39
40
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
40
41
|
import { createHash } from "node:crypto";
|
|
41
|
-
import { dispatchReplyWithBufferedBlockDispatcher,
|
|
42
|
+
import { dispatchReplyWithBufferedBlockDispatcher, resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
|
|
42
43
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
43
44
|
import { createInboundDebouncer, resolveInboundDebounceMs } from "openclaw/plugin-sdk/channel-inbound-debounce";
|
|
44
|
-
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
45
|
-
import { hasControlCommand, isControlCommandMessage, isControlCommandMessage as isControlCommandMessage$1, shouldComputeCommandAuthorized } from "openclaw/plugin-sdk/command-detection";
|
|
46
45
|
import { drainPendingDeliveries } from "openclaw/plugin-sdk/delivery-queue-runtime";
|
|
47
46
|
import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
48
47
|
import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
48
|
+
import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
49
|
+
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
50
|
+
import { saveMediaStream } from "openclaw/plugin-sdk/media-store";
|
|
51
51
|
import { getRuntimeConfig as getRuntimeConfig$1, getRuntimeConfigSourceSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
52
52
|
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
53
53
|
import { buildMentionRegexes, implicitMentionKindWhen, normalizeMentionText, resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-mention-gating";
|
|
@@ -55,60 +55,27 @@ import { createConnectedChannelStatusPatch, createTransportActivityStatusPatch }
|
|
|
55
55
|
import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute } from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
56
56
|
import { resolveAgentIdentity, resolveIdentityNamePrefix as resolveIdentityNamePrefix$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
57
57
|
import { normalizeGroupActivation, parseActivationCommand } from "openclaw/plugin-sdk/group-activation";
|
|
58
|
+
import { hasControlCommand, isControlCommandMessage, shouldComputeCommandAuthorized } from "openclaw/plugin-sdk/command-detection";
|
|
58
59
|
import { createInternalHookEvent, deriveInboundMessageHookContext, fireAndForgetBoundedHook, toInternalMessageReceivedContext, toPluginMessageContext, toPluginMessageReceivedEvent, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
|
|
59
60
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
60
61
|
import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
|
|
62
|
+
import { createChannelApiRetryRunner } from "openclaw/plugin-sdk/retry-runtime";
|
|
61
63
|
//#region extensions/whatsapp/src/inbound/dedupe.ts
|
|
62
64
|
const WHATSAPP_INBOUND_DEDUPE_TTL_MS = 20 * 6e4;
|
|
63
65
|
const RECENT_WEB_MESSAGE_MAX = 5e3;
|
|
64
66
|
const RECENT_OUTBOUND_MESSAGE_TTL_MS = 20 * 6e4;
|
|
65
67
|
const RECENT_OUTBOUND_MESSAGE_MAX = 5e3;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const whatsAppInboundReplayGuard = createChannelReplayGuard({
|
|
69
|
+
dedupe: {
|
|
70
|
+
ttlMs: WHATSAPP_INBOUND_DEDUPE_TTL_MS,
|
|
71
|
+
memoryMaxSize: RECENT_WEB_MESSAGE_MAX
|
|
72
|
+
},
|
|
73
|
+
buildReplayKey: (keys) => keys
|
|
69
74
|
});
|
|
70
|
-
const recentOutboundMessages =
|
|
75
|
+
const recentOutboundMessages = createDedupeCache({
|
|
71
76
|
ttlMs: RECENT_OUTBOUND_MESSAGE_TTL_MS,
|
|
72
77
|
maxSize: RECENT_OUTBOUND_MESSAGE_MAX
|
|
73
78
|
});
|
|
74
|
-
function createRecentMessageCache(options) {
|
|
75
|
-
const ttlMs = Math.max(0, options.ttlMs);
|
|
76
|
-
const maxSize = Math.max(0, Math.floor(options.maxSize));
|
|
77
|
-
const cache = /* @__PURE__ */ new Map();
|
|
78
|
-
const prune = (now) => {
|
|
79
|
-
if (ttlMs > 0) {
|
|
80
|
-
const cutoff = now - ttlMs;
|
|
81
|
-
for (const [key, timestamp] of cache) if (timestamp < cutoff) cache.delete(key);
|
|
82
|
-
}
|
|
83
|
-
while (cache.size > maxSize) {
|
|
84
|
-
const oldest = cache.keys().next().value;
|
|
85
|
-
if (!oldest) break;
|
|
86
|
-
cache.delete(oldest);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
const peek = (key, now = Date.now()) => {
|
|
90
|
-
if (!key) return false;
|
|
91
|
-
const timestamp = cache.get(key);
|
|
92
|
-
if (timestamp === void 0) return false;
|
|
93
|
-
if (ttlMs > 0 && now - timestamp >= ttlMs) {
|
|
94
|
-
cache.delete(key);
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
|
-
return {
|
|
100
|
-
check: (key, now = Date.now()) => {
|
|
101
|
-
if (!key) return false;
|
|
102
|
-
const existed = peek(key, now);
|
|
103
|
-
cache.delete(key);
|
|
104
|
-
cache.set(key, now);
|
|
105
|
-
prune(now);
|
|
106
|
-
return existed;
|
|
107
|
-
},
|
|
108
|
-
peek,
|
|
109
|
-
clear: () => cache.clear()
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
79
|
var WhatsAppRetryableInboundError = class extends Error {
|
|
113
80
|
constructor(message, options) {
|
|
114
81
|
super(message, options);
|
|
@@ -123,18 +90,9 @@ function buildMessageKey(params) {
|
|
|
123
90
|
return `${accountId}:${remoteJid}:${messageId}`;
|
|
124
91
|
}
|
|
125
92
|
function resetWebInboundDedupe() {
|
|
126
|
-
|
|
93
|
+
whatsAppInboundReplayGuard.clearMemory();
|
|
127
94
|
recentOutboundMessages.clear();
|
|
128
95
|
}
|
|
129
|
-
async function claimRecentInboundMessageDelivery(key) {
|
|
130
|
-
return (await claimableInboundMessages.claim(key)).kind;
|
|
131
|
-
}
|
|
132
|
-
async function commitRecentInboundMessage(key) {
|
|
133
|
-
await claimableInboundMessages.commit(key);
|
|
134
|
-
}
|
|
135
|
-
function releaseRecentInboundMessage(key, error) {
|
|
136
|
-
claimableInboundMessages.release(key, { error });
|
|
137
|
-
}
|
|
138
96
|
function rememberRecentOutboundMessage(params) {
|
|
139
97
|
const key = buildMessageKey(params);
|
|
140
98
|
if (!key) return;
|
|
@@ -570,12 +528,13 @@ async function downloadQuotedInboundMedia(msg, sock, maxBytes = 50 * 1024 * 1024
|
|
|
570
528
|
}
|
|
571
529
|
//#endregion
|
|
572
530
|
//#region extensions/whatsapp/src/inbound/monitor.ts
|
|
573
|
-
const LOGGED_OUT_STATUS = DisconnectReason
|
|
531
|
+
const LOGGED_OUT_STATUS = DisconnectReason.loggedOut;
|
|
574
532
|
const RECONNECT_IN_PROGRESS_ERROR = "no active socket - reconnection in progress";
|
|
575
533
|
const GROUP_META_TTL_MS = 300 * 1e3;
|
|
576
534
|
const BAILEYS_MESSAGE_TTL_MS = 600 * 1e3;
|
|
577
535
|
const INBOUND_CLOSE_DRAIN_TIMEOUT_MS = 5e3;
|
|
578
536
|
const REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE = /reply session initialization conflicted for \S+/u;
|
|
537
|
+
const WHATSAPP_GROUP_METADATA_CACHE_MAX_ENTRIES = 500;
|
|
579
538
|
function resolveRetryableWhatsAppInboundError(error) {
|
|
580
539
|
if (error instanceof WhatsAppRetryableInboundError) return error;
|
|
581
540
|
if (!collectErrorGraphCandidates(error, (current) => [current.cause, current.error]).some((candidate) => REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE.test(formatErrorMessage(candidate)))) return null;
|
|
@@ -598,7 +557,7 @@ function rememberGroupMetadataCacheEntry(cache, jid, entry) {
|
|
|
598
557
|
}
|
|
599
558
|
if (cache.has(jid)) cache.delete(jid);
|
|
600
559
|
cache.set(jid, entry);
|
|
601
|
-
while (cache.size >
|
|
560
|
+
while (cache.size > WHATSAPP_GROUP_METADATA_CACHE_MAX_ENTRIES) {
|
|
602
561
|
const oldest = cache.keys().next();
|
|
603
562
|
if (oldest.done) break;
|
|
604
563
|
cache.delete(oldest.value);
|
|
@@ -624,7 +583,7 @@ function rememberWhatsAppBaileysCacheEntry(cache, key, value, ttlMs) {
|
|
|
624
583
|
expiresAt: Date.now() + ttlMs,
|
|
625
584
|
value
|
|
626
585
|
});
|
|
627
|
-
while (cache.size >
|
|
586
|
+
while (cache.size > WHATSAPP_GROUP_METADATA_CACHE_MAX_ENTRIES) {
|
|
628
587
|
const oldest = cache.keys().next();
|
|
629
588
|
if (oldest.done) break;
|
|
630
589
|
cache.delete(oldest.value);
|
|
@@ -645,9 +604,6 @@ function logWhatsAppVerbose(enabled, message) {
|
|
|
645
604
|
if (!enabled) return;
|
|
646
605
|
defaultRuntime.log(message);
|
|
647
606
|
}
|
|
648
|
-
function isGroupJid(jid) {
|
|
649
|
-
return (typeof isJidGroup === "function" ? isJidGroup(jid) : jid.endsWith("@g.us")) === true;
|
|
650
|
-
}
|
|
651
607
|
function isDirectUserJid(jid) {
|
|
652
608
|
return /^(\d+)(?::\d+)?@(s\.whatsapp\.net|c\.us|lid|hosted|hosted\.lid)$/i.test(jid.trim());
|
|
653
609
|
}
|
|
@@ -711,7 +667,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
711
667
|
if (!options.socketRef) return sock;
|
|
712
668
|
if (options.socketRef.current) return options.socketRef.current;
|
|
713
669
|
if (!self.e164 && !self.jid && !self.lid) return null;
|
|
714
|
-
const successor =
|
|
670
|
+
const successor = getWhatsAppConnectionController(options.accountId);
|
|
715
671
|
if (!successor) return null;
|
|
716
672
|
const successorIdentity = successor.getSelfIdentity();
|
|
717
673
|
if (!successorIdentity || !identitiesOverlap(self, successorIdentity)) return null;
|
|
@@ -740,16 +696,16 @@ async function attachWebInboxToSocket(options) {
|
|
|
740
696
|
return (a.receiveOrder ?? 0) - (b.receiveOrder ?? 0);
|
|
741
697
|
});
|
|
742
698
|
const finalizeInboundDelivery = async (entries, error) => {
|
|
743
|
-
const
|
|
699
|
+
const replayClaims = entries.map((entry) => entry.replayClaim).filter((claim) => claim !== void 0);
|
|
744
700
|
const durableEntries = entries.filter((entry) => isNonEmptyString(entry.durableId));
|
|
745
701
|
const readReceiptEntries = entries.filter((entry) => Boolean(entry.readReceipt));
|
|
746
702
|
const retryableError = resolveRetryableWhatsAppInboundError(error);
|
|
747
703
|
if (retryableError) {
|
|
748
|
-
|
|
704
|
+
for (const claim of replayClaims) claim.release({ error: retryableError });
|
|
749
705
|
await Promise.all(durableEntries.map((entry) => durableInboundJournal.release(entry.durableId, { lastError: formatError(retryableError) })));
|
|
750
706
|
return;
|
|
751
707
|
}
|
|
752
|
-
await Promise.all([...
|
|
708
|
+
await Promise.all([...replayClaims.map((claim) => claim.commit()), ...durableEntries.map((entry) => durableInboundJournal.complete(entry.durableId, entry.readReceipt ? { metadata: { readReceipt: entry.readReceipt } } : void 0))]);
|
|
753
709
|
await Promise.all(readReceiptEntries.map((entry) => maybeMarkInboundAsRead(entry.readReceipt)));
|
|
754
710
|
};
|
|
755
711
|
const debouncer = createInboundDebouncer({
|
|
@@ -988,7 +944,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
988
944
|
}
|
|
989
945
|
};
|
|
990
946
|
const resolveOutboundMentionsForGroup = async (jid, text) => {
|
|
991
|
-
if (
|
|
947
|
+
if (isJidGroup(jid) !== true || !mayContainWhatsAppOutboundMention(text)) return {
|
|
992
948
|
text,
|
|
993
949
|
mentionedJids: []
|
|
994
950
|
};
|
|
@@ -1021,7 +977,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1021
977
|
const remoteJid = msg.key?.remoteJid;
|
|
1022
978
|
if (!remoteJid) return null;
|
|
1023
979
|
if (remoteJid.endsWith("@status") || remoteJid.endsWith("@broadcast")) return null;
|
|
1024
|
-
const group =
|
|
980
|
+
const group = isJidGroup(remoteJid) === true;
|
|
1025
981
|
if (Boolean(msg.key?.fromMe) && id && isRecentOutboundMessage({
|
|
1026
982
|
accountId: options.accountId,
|
|
1027
983
|
remoteJid,
|
|
@@ -1162,9 +1118,9 @@ async function attachWebInboxToSocket(options) {
|
|
|
1162
1118
|
return;
|
|
1163
1119
|
}
|
|
1164
1120
|
const dedupeKey = inbound.id ? `${options.accountId}:${inbound.remoteJid}:${inbound.id}` : "";
|
|
1165
|
-
const dedupeClaim = dedupeKey ? await
|
|
1166
|
-
if (dedupeClaim
|
|
1167
|
-
if (dedupeClaim === "duplicate") {
|
|
1121
|
+
const dedupeClaim = dedupeKey ? await whatsAppInboundReplayGuard.claim(dedupeKey) : { kind: "invalid" };
|
|
1122
|
+
if (dedupeClaim.kind === "duplicate" || dedupeClaim.kind === "inflight") {
|
|
1123
|
+
if (dedupeClaim.kind === "duplicate") {
|
|
1168
1124
|
await completeUndeliverableDurableInbound(durableId, durableMetadata);
|
|
1169
1125
|
await maybeMarkNonSelfChatReadReceipt(inbound, deliveryReadReceipt);
|
|
1170
1126
|
}
|
|
@@ -1174,7 +1130,8 @@ async function attachWebInboxToSocket(options) {
|
|
|
1174
1130
|
await enqueueInboundMessage(msg, inbound, enriched, {
|
|
1175
1131
|
durableId,
|
|
1176
1132
|
readReceipt: deliveryReadReceipt,
|
|
1177
|
-
receiveOrder
|
|
1133
|
+
receiveOrder,
|
|
1134
|
+
...dedupeClaim.kind === "claimed" ? { replayClaim: dedupeClaim.handle } : {}
|
|
1178
1135
|
});
|
|
1179
1136
|
};
|
|
1180
1137
|
const replayPendingDurableInboundMessages = async () => {
|
|
@@ -1339,7 +1296,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
1339
1296
|
}
|
|
1340
1297
|
} : void 0,
|
|
1341
1298
|
group,
|
|
1342
|
-
|
|
1299
|
+
replayClaim: durable.replayClaim,
|
|
1343
1300
|
durableId: durable.durableId,
|
|
1344
1301
|
readReceipt: durable.readReceipt,
|
|
1345
1302
|
receiveOrder: durable.receiveOrder
|
|
@@ -1770,7 +1727,7 @@ function createEchoTracker(params) {
|
|
|
1770
1727
|
sessionKey: opts.combinedBodySessionKey,
|
|
1771
1728
|
combinedBody: opts.combinedBody
|
|
1772
1729
|
}));
|
|
1773
|
-
if (opts.logVerboseMessage) params.logVerbose?.(`Added to echo detection set (size now: ${recentlySent.size}): ${text
|
|
1730
|
+
if (opts.logVerboseMessage) params.logVerbose?.(`Added to echo detection set (size now: ${recentlySent.size}): ${truncateUtf16Safe(text, 50)}...`);
|
|
1774
1731
|
trim();
|
|
1775
1732
|
};
|
|
1776
1733
|
return {
|
|
@@ -1831,19 +1788,20 @@ async function resolveGroupActivationFor(params) {
|
|
|
1831
1788
|
sessionKey: params.sessionKey
|
|
1832
1789
|
});
|
|
1833
1790
|
const activation = (normalizeAccountId$1(params.accountId) === DEFAULT_ACCOUNT_ID$1 && hasNamedWhatsAppAccounts(params.cfg) && isActivationOnlyEntry(scopedEntry) ? void 0 : scopedEntry?.groupActivation) ?? legacyEntry?.groupActivation;
|
|
1834
|
-
if (activation !== void 0 && scopedEntry?.groupActivation === void 0)
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1791
|
+
if (activation !== void 0 && scopedEntry?.groupActivation === void 0) {
|
|
1792
|
+
if (scopedEntry) await patchSessionEntry({
|
|
1793
|
+
...sessionScope,
|
|
1794
|
+
sessionKey: params.sessionKey,
|
|
1795
|
+
replaceEntry: true,
|
|
1796
|
+
update: (entry) => {
|
|
1797
|
+
if (entry.groupActivation !== void 0) return null;
|
|
1798
|
+
return {
|
|
1799
|
+
...entry,
|
|
1800
|
+
groupActivation: activation
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1847
1805
|
const defaultActivation = !resolveWhatsAppInboundPolicy({
|
|
1848
1806
|
cfg: params.cfg,
|
|
1849
1807
|
accountId: params.accountId
|
|
@@ -2043,17 +2001,12 @@ function formatGroupMembers(params) {
|
|
|
2043
2001
|
}
|
|
2044
2002
|
//#endregion
|
|
2045
2003
|
//#region extensions/whatsapp/src/auto-reply/monitor/group-gating.ts
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2004
|
+
const groupDropWarned = createDedupeCache({
|
|
2005
|
+
ttlMs: 0,
|
|
2006
|
+
maxSize: 100
|
|
2007
|
+
});
|
|
2048
2008
|
function shouldWarnForGroupDrop(warnKey) {
|
|
2049
|
-
|
|
2050
|
-
groupDropWarned.add(warnKey);
|
|
2051
|
-
while (groupDropWarned.size > MAX_GROUP_DROP_WARNINGS) {
|
|
2052
|
-
const oldest = groupDropWarned.values().next().value;
|
|
2053
|
-
if (!oldest) break;
|
|
2054
|
-
groupDropWarned.delete(oldest);
|
|
2055
|
-
}
|
|
2056
|
-
return true;
|
|
2009
|
+
return !groupDropWarned.check(warnKey);
|
|
2057
2010
|
}
|
|
2058
2011
|
function isOwnerSender(baseMentionConfig, msg, authDir) {
|
|
2059
2012
|
const sender = normalizeE164(getSenderIdentity(msg, authDir).e164 ?? "");
|
|
@@ -2250,6 +2203,57 @@ function resolveWhatsAppDirectSystemPrompt(params) {
|
|
|
2250
2203
|
return wildcard != null ? wildcard.trim() || void 0 : void 0;
|
|
2251
2204
|
}
|
|
2252
2205
|
//#endregion
|
|
2206
|
+
//#region extensions/whatsapp/src/outbound-retry.ts
|
|
2207
|
+
const WHATSAPP_OUTBOUND_MAX_ATTEMPTS = 3;
|
|
2208
|
+
const WHATSAPP_OUTBOUND_MIN_DELAY_MS = 500;
|
|
2209
|
+
const WHATSAPP_OUTBOUND_MAX_DELAY_MS = 1e3;
|
|
2210
|
+
const WHATSAPP_RETRYABLE_OUTBOUND_ERROR_PATTERN = /closed|reset|timed\s*out|disconnect/i;
|
|
2211
|
+
var WhatsAppOutboundRetryError = class extends Error {
|
|
2212
|
+
constructor(original) {
|
|
2213
|
+
super(formatError(original), { cause: original });
|
|
2214
|
+
this.original = original;
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
function isRetryableWhatsAppOutboundError(error) {
|
|
2218
|
+
if (isWhatsAppSocketOperationTimeoutError(error)) return false;
|
|
2219
|
+
return WHATSAPP_RETRYABLE_OUTBOUND_ERROR_PATTERN.test(formatError(error));
|
|
2220
|
+
}
|
|
2221
|
+
async function sendWhatsAppOutboundWithRetry(params) {
|
|
2222
|
+
const runWithRetry = createChannelApiRetryRunner({
|
|
2223
|
+
retry: {
|
|
2224
|
+
attempts: WHATSAPP_OUTBOUND_MAX_ATTEMPTS,
|
|
2225
|
+
minDelayMs: WHATSAPP_OUTBOUND_MIN_DELAY_MS,
|
|
2226
|
+
maxDelayMs: WHATSAPP_OUTBOUND_MAX_DELAY_MS,
|
|
2227
|
+
jitter: 0
|
|
2228
|
+
},
|
|
2229
|
+
strictShouldRetry: true,
|
|
2230
|
+
retryAfterMs: () => void 0,
|
|
2231
|
+
shouldRetry: (error, attempt) => {
|
|
2232
|
+
if (!(error instanceof WhatsAppOutboundRetryError) || !isRetryableWhatsAppOutboundError(error.original)) return false;
|
|
2233
|
+
params.onRetry?.({
|
|
2234
|
+
attempt,
|
|
2235
|
+
maxAttempts: WHATSAPP_OUTBOUND_MAX_ATTEMPTS,
|
|
2236
|
+
backoffMs: Math.min(WHATSAPP_OUTBOUND_MIN_DELAY_MS * 2 ** (attempt - 1), WHATSAPP_OUTBOUND_MAX_DELAY_MS),
|
|
2237
|
+
error: error.original,
|
|
2238
|
+
errorText: formatError(error.original)
|
|
2239
|
+
});
|
|
2240
|
+
return true;
|
|
2241
|
+
}
|
|
2242
|
+
});
|
|
2243
|
+
try {
|
|
2244
|
+
return await runWithRetry(async () => {
|
|
2245
|
+
try {
|
|
2246
|
+
return await params.send();
|
|
2247
|
+
} catch (error) {
|
|
2248
|
+
throw new WhatsAppOutboundRetryError(error);
|
|
2249
|
+
}
|
|
2250
|
+
});
|
|
2251
|
+
} catch (error) {
|
|
2252
|
+
if (error instanceof WhatsAppOutboundRetryError) throw error.original;
|
|
2253
|
+
throw error;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
//#endregion
|
|
2253
2257
|
//#region extensions/whatsapp/src/auto-reply/util.ts
|
|
2254
2258
|
function elide(text, limit = 400) {
|
|
2255
2259
|
if (!text) return text;
|
|
@@ -2369,11 +2373,10 @@ async function deliverWebReply(params) {
|
|
|
2369
2373
|
messageText: cached?.body ?? ""
|
|
2370
2374
|
});
|
|
2371
2375
|
};
|
|
2372
|
-
const sendWithRetry = async (fn, label
|
|
2376
|
+
const sendWithRetry = async (fn, label) => {
|
|
2373
2377
|
try {
|
|
2374
2378
|
return await sendWhatsAppOutboundWithRetry({
|
|
2375
2379
|
send: fn,
|
|
2376
|
-
maxAttempts,
|
|
2377
2380
|
onRetry: ({ attempt, maxAttempts: retryMaxAttempts, backoffMs, errorText }) => {
|
|
2378
2381
|
logVerbose(`Retrying ${label} to ${conversationId} after failure (${attempt}/${retryMaxAttempts - 1}) in ${backoffMs}ms: ${errorText}`);
|
|
2379
2382
|
}
|
|
@@ -2575,8 +2578,8 @@ function resolveWhatsAppDurableReplyToId(params) {
|
|
|
2575
2578
|
return null;
|
|
2576
2579
|
}
|
|
2577
2580
|
function resolveWhatsAppDisableBlockStreaming(cfg) {
|
|
2578
|
-
|
|
2579
|
-
return !
|
|
2581
|
+
const enabled = resolveChannelStreamingBlockEnabled(cfg.channels?.whatsapp);
|
|
2582
|
+
return typeof enabled === "boolean" ? !enabled : void 0;
|
|
2580
2583
|
}
|
|
2581
2584
|
function resolveWhatsAppDeliverablePayload(payload, info) {
|
|
2582
2585
|
if (payload.isReasoning === true || payload.isCompactionNotice === true) return null;
|
|
@@ -2659,7 +2662,6 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2659
2662
|
}] : void 0, { transcribed: (_entry, index) => params.mediaTranscribedIndexes?.includes(index) === true });
|
|
2660
2663
|
return buildChannelInboundEventContext({
|
|
2661
2664
|
channel: "whatsapp",
|
|
2662
|
-
finalize: finalizeInboundContext,
|
|
2663
2665
|
supplemental: {
|
|
2664
2666
|
quote: params.visibleReplyTo ? {
|
|
2665
2667
|
id: params.visibleReplyTo.id,
|
|
@@ -2696,7 +2698,7 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2696
2698
|
bodyForAgent: params.bodyForAgent ?? params.msg.payload.body,
|
|
2697
2699
|
inboundHistory,
|
|
2698
2700
|
rawBody: params.rawBody ?? params.msg.payload.body,
|
|
2699
|
-
commandBody: params.
|
|
2701
|
+
commandBody: params.command?.body ?? params.msg.payload.body
|
|
2700
2702
|
},
|
|
2701
2703
|
access: {
|
|
2702
2704
|
...wasMentioned !== void 0 ? { mentions: {
|
|
@@ -2704,9 +2706,9 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2704
2706
|
wasMentioned,
|
|
2705
2707
|
requireMention: params.msg.groupMention?.requireMention
|
|
2706
2708
|
} } : {},
|
|
2707
|
-
commands: { authorized: params.
|
|
2709
|
+
commands: { authorized: params.command?.authorized === true }
|
|
2708
2710
|
},
|
|
2709
|
-
|
|
2711
|
+
command: params.command,
|
|
2710
2712
|
extra: {
|
|
2711
2713
|
Transcript: params.transcript,
|
|
2712
2714
|
GroupSubject: params.msg.group?.subject,
|
|
@@ -2716,40 +2718,12 @@ async function buildWhatsAppInboundContext(params) {
|
|
|
2716
2718
|
fallbackE164: params.sender.e164
|
|
2717
2719
|
}),
|
|
2718
2720
|
SenderE164: params.sender.e164,
|
|
2719
|
-
CommandSource: params.commandSource ?? (params.commandTurn?.source === "native" || params.commandTurn?.source === "text" ? params.commandTurn.source : void 0),
|
|
2720
2721
|
ReplyThreading: params.replyThreading,
|
|
2721
2722
|
SuppressMessageReceivedHooks: params.suppressMessageReceivedHooks,
|
|
2722
2723
|
...params.msg.payload.location ? toLocationContext(params.msg.payload.location) : {}
|
|
2723
2724
|
}
|
|
2724
2725
|
});
|
|
2725
2726
|
}
|
|
2726
|
-
function normalizeCommandTurnFromContext(value) {
|
|
2727
|
-
if (!value || typeof value !== "object") return;
|
|
2728
|
-
const record = value;
|
|
2729
|
-
const kind = record.kind;
|
|
2730
|
-
const source = record.source;
|
|
2731
|
-
if (kind === "native" && source === "native" && typeof record.authorized === "boolean") return {
|
|
2732
|
-
kind: "native",
|
|
2733
|
-
source: "native",
|
|
2734
|
-
authorized: record.authorized,
|
|
2735
|
-
commandName: typeof record.commandName === "string" ? record.commandName : void 0,
|
|
2736
|
-
body: typeof record.body === "string" ? record.body : void 0
|
|
2737
|
-
};
|
|
2738
|
-
if (kind === "text-slash" && source === "text" && typeof record.authorized === "boolean") return {
|
|
2739
|
-
kind: "text-slash",
|
|
2740
|
-
source: "text",
|
|
2741
|
-
authorized: record.authorized,
|
|
2742
|
-
commandName: typeof record.commandName === "string" ? record.commandName : void 0,
|
|
2743
|
-
body: typeof record.body === "string" ? record.body : void 0
|
|
2744
|
-
};
|
|
2745
|
-
if (kind === "normal" && source === "message") return {
|
|
2746
|
-
kind: "normal",
|
|
2747
|
-
source: "message",
|
|
2748
|
-
authorized: false,
|
|
2749
|
-
commandName: typeof record.commandName === "string" ? record.commandName : void 0,
|
|
2750
|
-
body: typeof record.body === "string" ? record.body : void 0
|
|
2751
|
-
};
|
|
2752
|
-
}
|
|
2753
2727
|
function resolveWhatsAppDmRouteTarget(params) {
|
|
2754
2728
|
const admission = requireWhatsAppInboundAdmission(params.msg);
|
|
2755
2729
|
const conversationId = admission.conversation.id;
|
|
@@ -2798,18 +2772,9 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
2798
2772
|
accountId: params.route.accountId
|
|
2799
2773
|
});
|
|
2800
2774
|
const mediaLocalRoots = getAgentScopedMediaLocalRoots(params.cfg, params.route.agentId);
|
|
2801
|
-
const
|
|
2802
|
-
const sourceReplyCommandSource = params.context.CommandSource === "native" || params.context.CommandSource === "text" ? params.context.CommandSource : void 0;
|
|
2803
|
-
const sourceReplyCommandTurn = normalizeCommandTurnFromContext(params.context.CommandTurn);
|
|
2804
|
-
const sourceReplyCommandAuthorized = typeof params.context.CommandAuthorized === "boolean" ? params.context.CommandAuthorized : void 0;
|
|
2805
|
-
const sourceReplyDeliveryMode = sourceReplyChatType === "group" || sourceReplyChatType === "channel" ? resolveChannelMessageSourceReplyDeliveryMode({
|
|
2775
|
+
const sourceReplyDeliveryMode = params.context.ChatType === "group" || params.context.ChatType === "channel" ? resolveChannelMessageSourceReplyDeliveryMode({
|
|
2806
2776
|
cfg: params.cfg,
|
|
2807
|
-
ctx:
|
|
2808
|
-
ChatType: sourceReplyChatType,
|
|
2809
|
-
CommandTurn: sourceReplyCommandTurn,
|
|
2810
|
-
CommandSource: sourceReplyCommandSource,
|
|
2811
|
-
CommandAuthorized: sourceReplyCommandAuthorized
|
|
2812
|
-
}
|
|
2777
|
+
ctx: params.context
|
|
2813
2778
|
}) : void 0;
|
|
2814
2779
|
const sourceRepliesAreToolOnly = sourceReplyDeliveryMode === "message_tool_only";
|
|
2815
2780
|
const disableBlockStreaming = sourceRepliesAreToolOnly ? true : resolveWhatsAppDisableBlockStreaming(params.cfg);
|
|
@@ -3340,24 +3305,13 @@ async function processMessage(params) {
|
|
|
3340
3305
|
normalizeE164
|
|
3341
3306
|
});
|
|
3342
3307
|
const shouldCheckCommandAuth = shouldComputeCommandAuthorized(commandBody, params.cfg);
|
|
3343
|
-
const isTextCommand = isControlCommandMessage
|
|
3308
|
+
const isTextCommand = isControlCommandMessage(commandBody, params.cfg);
|
|
3344
3309
|
const commandAuthorized = shouldCheckCommandAuth ? await resolveWhatsAppCommandAuthorized({
|
|
3345
3310
|
cfg: params.cfg,
|
|
3346
3311
|
msg: params.msg,
|
|
3347
3312
|
policy: inboundPolicy,
|
|
3348
3313
|
authDir: account.authDir
|
|
3349
3314
|
}) : void 0;
|
|
3350
|
-
const commandTurn = isTextCommand ? {
|
|
3351
|
-
kind: "text-slash",
|
|
3352
|
-
source: "text",
|
|
3353
|
-
authorized: Boolean(commandAuthorized),
|
|
3354
|
-
body: commandBody
|
|
3355
|
-
} : {
|
|
3356
|
-
kind: "normal",
|
|
3357
|
-
source: "message",
|
|
3358
|
-
authorized: false,
|
|
3359
|
-
body: commandBody
|
|
3360
|
-
};
|
|
3361
3315
|
const { onModelSelected, ...replyPipeline } = createChannelMessageReplyPipeline({
|
|
3362
3316
|
cfg: params.cfg,
|
|
3363
3317
|
agentId: params.route.agentId,
|
|
@@ -3381,9 +3335,11 @@ async function processMessage(params) {
|
|
|
3381
3335
|
const ctxPayload = await buildWhatsAppInboundContext({
|
|
3382
3336
|
bodyForAgent: msgForAgent.payload.body,
|
|
3383
3337
|
combinedBody,
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3338
|
+
command: {
|
|
3339
|
+
kind: isTextCommand ? "text-slash" : "normal",
|
|
3340
|
+
body: commandBody,
|
|
3341
|
+
authorized: commandAuthorized
|
|
3342
|
+
},
|
|
3387
3343
|
groupHistory: visibleGroupHistory,
|
|
3388
3344
|
groupMemberRoster: params.groupMemberNames.get(params.groupHistoryKey),
|
|
3389
3345
|
groupSystemPrompt: conversationSystemPrompt,
|
|
@@ -3811,9 +3767,8 @@ function resolveWebMonitorConfigSnapshot(params) {
|
|
|
3811
3767
|
groupAllowFrom: account.groupAllowFrom,
|
|
3812
3768
|
groupPolicy: account.groupPolicy,
|
|
3813
3769
|
textChunkLimit: account.textChunkLimit,
|
|
3814
|
-
|
|
3770
|
+
streaming: account.streaming,
|
|
3815
3771
|
mediaMaxMb: account.mediaMaxMb,
|
|
3816
|
-
blockStreaming: account.blockStreaming,
|
|
3817
3772
|
groups: account.groups
|
|
3818
3773
|
}
|
|
3819
3774
|
}
|
|
@@ -3928,10 +3883,12 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
3928
3883
|
});
|
|
3929
3884
|
const shouldDebounce = (msg) => {
|
|
3930
3885
|
const normalized = normalizeWebInboundMessage(msg);
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3886
|
+
return shouldDebounceTextInbound({
|
|
3887
|
+
text: normalized.payload.commandBody ?? normalized.payload.body,
|
|
3888
|
+
cfg,
|
|
3889
|
+
hasMedia: Boolean(normalized.payload.media?.path || normalized.payload.media?.type),
|
|
3890
|
+
allowDebounce: !(normalized.payload.location || normalized.quote?.id || normalized.quote?.body)
|
|
3891
|
+
});
|
|
3935
3892
|
};
|
|
3936
3893
|
let connection;
|
|
3937
3894
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
1
|
+
import { normalizeLowercaseStringOrEmpty, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
|
|
3
3
|
//#region extensions/whatsapp/src/normalize-target.ts
|
|
4
4
|
const WHATSAPP_USER_JID_RE = /^(\d+)(?::\d+)?@s\.whatsapp\.net$/i;
|
|
@@ -34,11 +34,20 @@ function isWhatsAppUserTarget(value) {
|
|
|
34
34
|
}
|
|
35
35
|
function extractUserJidPhone(jid) {
|
|
36
36
|
const userMatch = jid.match(WHATSAPP_USER_JID_RE);
|
|
37
|
-
if (userMatch)
|
|
37
|
+
if (userMatch) {
|
|
38
|
+
const phone = userMatch[1];
|
|
39
|
+
return phone ? phone : null;
|
|
40
|
+
}
|
|
38
41
|
const legacyUserMatch = jid.match(WHATSAPP_LEGACY_USER_JID_RE);
|
|
39
|
-
if (legacyUserMatch)
|
|
42
|
+
if (legacyUserMatch) {
|
|
43
|
+
const phone = legacyUserMatch[1];
|
|
44
|
+
return phone ? phone : null;
|
|
45
|
+
}
|
|
40
46
|
const lidMatch = jid.match(WHATSAPP_LID_RE);
|
|
41
|
-
if (lidMatch)
|
|
47
|
+
if (lidMatch) {
|
|
48
|
+
const phone = lidMatch[1];
|
|
49
|
+
return phone ? phone : null;
|
|
50
|
+
}
|
|
42
51
|
return null;
|
|
43
52
|
}
|
|
44
53
|
function normalizeWhatsAppTarget(value) {
|
|
@@ -67,12 +76,7 @@ function normalizeWhatsAppMessagingTarget(raw) {
|
|
|
67
76
|
return normalizeWhatsAppTarget(trimmed) ?? void 0;
|
|
68
77
|
}
|
|
69
78
|
function normalizeWhatsAppAllowFromEntries(allowFrom) {
|
|
70
|
-
|
|
71
|
-
return allowFrom.map((entry) => String(entry).trim()).filter((entry) => Boolean(entry)).map(normalizeWhatsAppAllowFromEntry).filter((entry) => Boolean(entry)).filter((entry) => {
|
|
72
|
-
if (seen.has(entry)) return false;
|
|
73
|
-
seen.add(entry);
|
|
74
|
-
return true;
|
|
75
|
-
});
|
|
79
|
+
return uniqueStrings(normalizeStringEntries(allowFrom).map(normalizeWhatsAppAllowFromEntry).filter((entry) => Boolean(entry)));
|
|
76
80
|
}
|
|
77
81
|
function normalizeWhatsAppAllowFromEntry(entry) {
|
|
78
82
|
if (entry === "*") return entry;
|