@openclaw/whatsapp 2026.7.2-beta.3 → 2026.7.2-beta.4

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.
Files changed (144) hide show
  1. package/dist/{access-control-tjy_em01.js → access-control-CRz_v6bR.js} +4 -5
  2. package/dist/{accounts-ejK8sXPU.js → accounts-CxPuEFi-.js} +1 -1
  3. package/dist/{action-runtime-p0V390gA.js → action-runtime-CHU7xb6o.js} +2 -2
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/action-runtime.runtime.js +1 -1
  6. package/dist/{active-listener-BbdlXooT.js → active-listener-BEjWsCNM.js} +1 -1
  7. package/dist/api.js +12 -15
  8. package/dist/{approval-handler.runtime-BO1oJ-b8.js → approval-handler.runtime-C4ddB7Kc.js} +4 -4
  9. package/dist/{approval-reactions-CrZFAyf-.js → approval-reactions-P2HXjmln.js} +3 -3
  10. package/dist/{auth-store-BQi9pZqQ.js → auth-store-DirYMTbo.js} +4 -3
  11. package/dist/call-tool-api.js +4 -4
  12. package/dist/{channel-B2I4Opzb.js → channel-B9xjrOGG.js} +28 -19
  13. package/dist/channel-config-api.js +1 -1
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/{channel-react-action-CPRQE-s3.js → channel-react-action-CBW-PA8q.js} +10 -13
  16. package/dist/{channel.runtime-CjkhQzk8.js → channel.runtime-DdKuhlNu.js} +5 -5
  17. package/dist/{channel.setup-BMWE9LmN.js → channel.setup-DXUCPHel.js} +3 -6
  18. package/dist/{config-schema-BZ8h1hWA.js → config-schema-C6IeKIC0.js} +6 -0
  19. package/dist/{connection-controller-HGaffeFb.js → connection-controller-BVRExqrB.js} +8 -10
  20. package/dist/{connection-controller-runtime-context-9mEeAvu1.js → connection-controller-runtime-context-DG0tuYuw.js} +3 -3
  21. package/dist/contract-api.js +1 -1
  22. package/dist/{directory-config-BZ775eGX.js → directory-config-BTbJkV1W.js} +5 -5
  23. package/dist/directory-contract-api.js +1 -1
  24. package/dist/doctor-CwzVXKoE.js +10 -0
  25. package/dist/doctor-contract-api.js +35 -79
  26. package/dist/{group-session-key-Dh8WZun_.js → group-session-key-DJSdYfnb.js} +9 -4
  27. package/dist/{identity-D7L8LCuH.js → identity-BM4_wZeM.js} +2 -2
  28. package/dist/light-runtime-api.js +2 -2
  29. package/dist/{login-ifOXCBjo.js → login-BKUm7KSk.js} +6 -7
  30. package/dist/{login-qr-DUHzVH_Y.js → login-qr-DagJvMbg.js} +7 -8
  31. package/dist/login-qr-runtime.js +1 -1
  32. package/dist/{monitor-_jqDKBXj.js → monitor-CBVNJ2lb.js} +206 -232
  33. package/dist/{question-reactions-C0qJ6wGA.js → question-reactions-CaOrSYzU.js} +1 -1
  34. package/dist/runtime-BLlToOi6.js +21 -0
  35. package/dist/runtime-api.js +10 -10
  36. package/dist/runtime-setter-api.js +1 -1
  37. package/dist/{send-SB-4JrVZ.js → send-DhJVN30g.js} +38 -84
  38. package/dist/{send-api-BG0MgoFI.js → send-api-CpHwbor_.js} +39 -33
  39. package/dist/{setup-finalize-Cc-4iWGj.js → setup-finalize-9XzKdFq6.js} +3 -3
  40. package/dist/setup-plugin-api.js +1 -1
  41. package/dist/{setup-surface-DhnXEZir.js → setup-surface-Kv3mPki2.js} +3 -3
  42. package/dist/{setup-core-BbIgEl2M.js → shared-CuqHFnKd.js} +78 -56
  43. package/dist/{socket-close-jNGyZY4T.js → socket-close-BoSHhQNJ.js} +5 -6
  44. package/dist/{targets-runtime-Bsh0HR9y.js → targets-runtime-CKFrhoX4.js} +142 -29
  45. package/dist/text-runtime-CU_IlbK5.js +4 -0
  46. package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
  47. package/node_modules/@protobufjs/utf8/index.js +29 -18
  48. package/node_modules/@protobufjs/utf8/package.json +2 -2
  49. package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
  50. package/node_modules/@thi.ng/bitstream/package.json +4 -4
  51. package/node_modules/@thi.ng/errors/package.json +4 -4
  52. package/node_modules/@types/node/README.md +1 -1
  53. package/node_modules/@types/node/fs/promises.d.ts +16 -6
  54. package/node_modules/@types/node/package.json +2 -2
  55. package/node_modules/audio-type/package.json +3 -2
  56. package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -1
  57. package/node_modules/lru-cache/dist/commonjs/browser/index.js +11 -4
  58. package/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -1
  59. package/node_modules/lru-cache/dist/commonjs/browser/index.min.js +1 -1
  60. package/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +3 -3
  61. package/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
  62. package/node_modules/lru-cache/dist/commonjs/index.js +11 -4
  63. package/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
  64. package/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
  65. package/node_modules/lru-cache/dist/commonjs/index.min.js.map +3 -3
  66. package/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -1
  67. package/node_modules/lru-cache/dist/commonjs/node/index.js +11 -4
  68. package/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -1
  69. package/node_modules/lru-cache/dist/commonjs/node/index.min.js +1 -1
  70. package/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +3 -3
  71. package/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -1
  72. package/node_modules/lru-cache/dist/esm/browser/index.js +11 -4
  73. package/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -1
  74. package/node_modules/lru-cache/dist/esm/browser/index.min.js +1 -1
  75. package/node_modules/lru-cache/dist/esm/browser/index.min.js.map +3 -3
  76. package/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
  77. package/node_modules/lru-cache/dist/esm/index.js +11 -4
  78. package/node_modules/lru-cache/dist/esm/index.js.map +1 -1
  79. package/node_modules/lru-cache/dist/esm/index.min.js +1 -1
  80. package/node_modules/lru-cache/dist/esm/index.min.js.map +3 -3
  81. package/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -1
  82. package/node_modules/lru-cache/dist/esm/node/index.js +11 -4
  83. package/node_modules/lru-cache/dist/esm/node/index.js.map +1 -1
  84. package/node_modules/lru-cache/dist/esm/node/index.min.js +1 -1
  85. package/node_modules/lru-cache/dist/esm/node/index.min.js.map +3 -3
  86. package/node_modules/lru-cache/package.json +1 -1
  87. package/node_modules/music-metadata/lib/common/Util.d.ts +1 -1
  88. package/node_modules/music-metadata/lib/common/Util.js +7 -1
  89. package/node_modules/music-metadata/lib/id3v2/FrameHeader.js +23 -3
  90. package/node_modules/music-metadata/lib/id3v2/FrameParser.js +2 -2
  91. package/node_modules/music-metadata/lib/id3v2/ID3v2Token.js +1 -1
  92. package/node_modules/music-metadata/lib/mp4/AtomToken.js +38 -13
  93. package/node_modules/music-metadata/lib/mpeg/MpegParser.js +1 -1
  94. package/node_modules/music-metadata/package.json +6 -6
  95. package/node_modules/p-queue/dist/index.js +17 -6
  96. package/node_modules/p-queue/package.json +1 -1
  97. package/node_modules/protobufjs/dist/light/protobuf.js +145 -188
  98. package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
  99. package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
  100. package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
  101. package/node_modules/protobufjs/dist/minimal/protobuf.js +33 -76
  102. package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
  103. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
  104. package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
  105. package/node_modules/protobufjs/dist/protobuf.js +168 -208
  106. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  107. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  108. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  109. package/node_modules/protobufjs/index.d.ts +0 -8
  110. package/node_modules/protobufjs/package.json +2 -3
  111. package/node_modules/protobufjs/src/parse.js +3 -0
  112. package/node_modules/protobufjs/src/util/minimal.js +0 -3
  113. package/node_modules/typebox/build/compile/validator.d.mts +1 -4
  114. package/node_modules/typebox/build/guard/guard.d.mts +1 -1
  115. package/node_modules/typebox/build/guard/guard.mjs +5 -2
  116. package/node_modules/typebox/build/guard/string.mjs +16 -4
  117. package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
  118. package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
  119. package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
  120. package/node_modules/typebox/build/typebox.d.mts +1 -1
  121. package/node_modules/typebox/build/typebox.mjs +1 -1
  122. package/node_modules/typebox/package.json +1 -1
  123. package/node_modules/typebox/readme.md +29 -32
  124. package/node_modules/ws/lib/receiver.js +15 -32
  125. package/node_modules/ws/lib/websocket-server.js +4 -4
  126. package/node_modules/ws/lib/websocket.js +4 -4
  127. package/node_modules/ws/package.json +5 -1
  128. package/npm-shrinkwrap.json +41 -45
  129. package/openclaw.plugin.json +139 -179
  130. package/package.json +21 -11
  131. package/dist/doctor-By3SB4lm.js +0 -48
  132. package/dist/runtime-BfAdAEYT.js +0 -8
  133. package/dist/text-runtime-BTGkMN0o.js +0 -4
  134. package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
  135. package/node_modules/@protobufjs/inquire/LICENSE +0 -26
  136. package/node_modules/@protobufjs/inquire/README.md +0 -13
  137. package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
  138. package/node_modules/@protobufjs/inquire/index.js +0 -38
  139. package/node_modules/@protobufjs/inquire/package.json +0 -21
  140. package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
  141. package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
  142. package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
  143. package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
  144. package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
@@ -1,42 +1,40 @@
1
- import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-ejK8sXPU.js";
2
- import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation, u as resolveWhatsAppReactionLevel } from "./send-SB-4JrVZ.js";
3
- import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
4
- import { r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-9mEeAvu1.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-Dh8WZun_.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";
1
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CxPuEFi-.js";
2
+ import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation, u as resolveWhatsAppReactionLevel } from "./send-DhJVN30g.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-CKFrhoX4.js";
6
+ import { t as normalizeE164 } from "./text-runtime-CU_IlbK5.js";
7
+ import { a as cacheInboundMessageMeta, i as buildQuotedMessageOptions, n as resolveWhatsAppGroupSessionRoute, o as lookupInboundMessageMeta, r as resolveWhatsAppLegacyGroupSessionKey } from "./group-session-key-DJSdYfnb.js";
8
+ import { g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-DirYMTbo.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-BM4_wZeM.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-jNGyZY4T.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-BoSHhQNJ.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-tjy_em01.js";
15
- 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-BG0MgoFI.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-HGaffeFb.js";
17
- import { n as maybeResolveWhatsAppApprovalReaction } from "./approval-reactions-CrZFAyf-.js";
18
- import { t as maybeResolveWhatsAppQuestionReaction } from "./question-reactions-C0qJ6wGA.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-CRz_v6bR.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-CpHwbor_.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-BVRExqrB.js";
17
+ import { n as maybeResolveWhatsAppApprovalReaction } from "./approval-reactions-P2HXjmln.js";
18
+ import { t as maybeResolveWhatsAppQuestionReaction } from "./question-reactions-CaOrSYzU.js";
19
19
  import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
20
20
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
21
21
  import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
22
- import { DEFAULT_TIMING, createAckReactionHandle, createStatusReactionController, logAckFailure, removeAckReactionHandleAfterReply, shouldAckReactionForWhatsApp } from "openclaw/plugin-sdk/channel-feedback";
22
+ import { createAckReactionHandle, createStatusReactionController, logAckFailure, removeAckReactionHandleAfterReply, shouldAckReactionForWhatsApp } from "openclaw/plugin-sdk/channel-feedback";
23
23
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-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
27
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
28
- import { DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressDrain, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
28
+ import { bindIngressLifecycleToReplyOptions, createChannelIngressMonitor, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
29
29
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
30
30
  import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
31
31
  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
32
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
34
- import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
33
+ import { buildChannelInboundEventContext, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundEnvelope as formatInboundEnvelope$1, formatInboundMediaUnavailableText, formatLocationText, formatMediaPlaceholderText, hasVisibleInboundReplyDispatch, resolveInboundSessionEnvelopeContext, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
35
34
  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
35
  import { asDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
37
36
  import { createHash } from "node:crypto";
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";
@@ -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) {
@@ -441,6 +440,8 @@ const WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES = 450;
441
440
  const WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES = 5e3;
442
441
  const WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS = 720 * 60 * 60 * 1e3;
443
442
  const WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS = 10080 * 60 * 1e3;
443
+ const WHATSAPP_DURABLE_INBOUND_PRUNE_INTERVAL_MS = 3600 * 1e3;
444
+ const WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION = 1;
444
445
  function hashNamespacePart(value) {
445
446
  return createHash("sha256").update(value).digest("hex").slice(0, 24);
446
447
  }
@@ -470,14 +471,6 @@ function createWhatsAppDurableInboundQueue(accountId) {
470
471
  async function enqueueWhatsAppDurableInbound(params) {
471
472
  const facts = inspectWhatsAppIngressMessage(params.message);
472
473
  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
474
  return await params.queue.enqueue(facts.eventId, {
482
475
  message: serializeWhatsAppDurableInboundMessage(params.message),
483
476
  upsertType: params.upsertType,
@@ -496,29 +489,52 @@ function resolveWhatsAppIngressNonRetryableFailure(error) {
496
489
  message: error.message
497
490
  } : null;
498
491
  }
499
- /** Core drain with per-conversation lanes and completion at reply-lane adoption. */
500
- function createWhatsAppIngressDrain(params) {
501
- return createChannelIngressDrain({
492
+ /** Shared monitor with per-conversation lanes and completion at reply-lane adoption. */
493
+ function createWhatsAppIngressMonitor(params) {
494
+ return createChannelIngressMonitor({
502
495
  queue: params.queue,
503
- retryPolicy: {
504
- maxAttempts: DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS,
505
- deadLetterMinAgeMs: DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS
496
+ inspect: (message) => inspectWhatsAppIngressMessage(message),
497
+ payload: {
498
+ version: WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION,
499
+ serialize: (message, { receivedAt }) => ({
500
+ message: serializeWhatsAppDurableInboundMessage(message),
501
+ receivedAt
502
+ }),
503
+ deserialize: (payload) => deserializeWhatsAppDurableInboundMessage(payload.message),
504
+ encode: ({ body }) => body,
505
+ decode: (payload) => ({
506
+ version: WHATSAPP_DURABLE_INBOUND_PAYLOAD_VERSION,
507
+ body: payload
508
+ }),
509
+ 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
510
  },
507
- resolveNonRetryableFailure: resolveWhatsAppIngressNonRetryableFailure,
508
- deriveLaneKey: (record) => {
509
- try {
510
- return inspectWhatsAppIngressMessage(deserializeWhatsAppDurableInboundMessage(record.payload.message)).laneKey;
511
- } catch {
512
- return record.id;
513
- }
511
+ deliver: (message, lifecycle, claim) => params.dispatch(message, claim.payload, lifecycle),
512
+ pollIntervalMs: params.pollIntervalMs,
513
+ retention: {
514
+ pruneIntervalMs: WHATSAPP_DURABLE_INBOUND_PRUNE_INTERVAL_MS,
515
+ pendingTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
516
+ pendingMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES,
517
+ completedTtlMs: WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS,
518
+ completedMaxEntries: WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES,
519
+ failedTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
520
+ failedMaxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES
521
+ },
522
+ drain: {
523
+ resolveNonRetryableFailure: resolveWhatsAppIngressNonRetryableFailure,
524
+ deriveLaneKey: (record) => {
525
+ try {
526
+ return inspectWhatsAppIngressMessage(deserializeWhatsAppDurableInboundMessage(record.payload.message)).laneKey;
527
+ } catch {
528
+ return record.id;
529
+ }
530
+ },
531
+ ...params.onLog ? { onLog: params.onLog } : {}
514
532
  },
515
- ...params.onLog ? { onLog: params.onLog } : {},
516
533
  ...params.abortSignal ? { abortSignal: params.abortSignal } : {},
517
- dispatchClaimedEvent: async (record, lifecycle) => {
518
- const message = deserializeWhatsAppDurableInboundMessage(record.payload.message);
519
- if (inspectWhatsAppIngressMessage(message).eventId !== record.id) throw new WhatsAppIngressPermanentError("event-id-mismatch", "WhatsApp ingress row id does not match its transport message key");
520
- return await params.dispatch(message, record.payload, lifecycle);
521
- }
534
+ admissionMode: "while-running",
535
+ createStoppedError: () => /* @__PURE__ */ new Error("WhatsApp ingress monitor is stopped."),
536
+ ...params.onError ? { onError: params.onError } : {},
537
+ ...params.onActivityChange ? { onActivityChange: params.onActivityChange } : {}
522
538
  });
523
539
  }
524
540
  //#endregion
@@ -738,6 +754,7 @@ async function attachWebInboxToSocket(options) {
738
754
  const pendingDebounceKeys = /* @__PURE__ */ new Set();
739
755
  const activeInboundFlushes = /* @__PURE__ */ new Set();
740
756
  const pendingMessageHandlers = /* @__PURE__ */ new Set();
757
+ let durableIngressActive = false;
741
758
  const debounceWorkWaiters = /* @__PURE__ */ new Set();
742
759
  const notifyDebounceWork = () => {
743
760
  if (debounceWorkWaiters.size === 0) return;
@@ -759,7 +776,7 @@ async function attachWebInboxToSocket(options) {
759
776
  };
760
777
  let nextReceiveOrder = 0;
761
778
  const publishPendingWorkState = (at = Date.now()) => {
762
- options.onPendingWorkChanged?.(pendingMessageHandlers.size + pendingDebounceKeys.size + activeInboundFlushes.size, at);
779
+ options.onPendingWorkChanged?.(pendingMessageHandlers.size + pendingDebounceKeys.size + activeInboundFlushes.size + (durableIngressActive ? 1 : 0), at);
763
780
  };
764
781
  const buildInboundDebounceKey = (msg) => {
765
782
  const admission = requireWhatsAppInboundAdmission(msg);
@@ -1192,17 +1209,19 @@ async function attachWebInboxToSocket(options) {
1192
1209
  const locationText = location ? formatLocationText(location) : void 0;
1193
1210
  const contactContext = extractContactContext(msg.message ?? void 0);
1194
1211
  const externalAdReplyContext = extractExternalAdReplyContext(msg.message ?? void 0);
1195
- const mediaPlaceholder = extractMediaPlaceholder(msg.message ?? void 0);
1212
+ let mediaKind = extractMediaKind(msg.message ?? void 0);
1196
1213
  let body = extractText(msg.message ?? void 0);
1197
1214
  if (locationText) body = [body, locationText].filter(Boolean).join("\n").trim();
1198
- if (!body) {
1199
- body = mediaPlaceholder;
1200
- if (!body) return null;
1201
- }
1215
+ if (!body && !mediaKind) return null;
1216
+ body = body ?? "";
1202
1217
  const commandBody = body;
1203
1218
  const replyContext = describeReplyContext(msg.message);
1204
1219
  let mediaPath;
1205
- let mediaType;
1220
+ let mediaType = mediaKind ? resolveInboundMediaMimetype(msg.message) : void 0;
1221
+ const nativeMedia = mediaKind ? {
1222
+ contentType: mediaType,
1223
+ kind: mediaKind
1224
+ } : void 0;
1206
1225
  let mediaFileName;
1207
1226
  const maxBytes = (typeof options.mediaMaxMb === "number" && options.mediaMaxMb > 0 ? options.mediaMaxMb : 50) * 1024 * 1024;
1208
1227
  const saveInboundMedia = async (inboundMedia) => {
@@ -1217,12 +1236,13 @@ async function attachWebInboxToSocket(options) {
1217
1236
  logWhatsAppVerbose(options.verbose, `Inbound media download failed: ${String(err)}`);
1218
1237
  body = formatInboundMediaUnavailableText({
1219
1238
  body,
1220
- mediaPlaceholder,
1221
1239
  notice: "[whatsapp attachment unavailable]"
1222
1240
  });
1223
1241
  }
1224
- if (!mediaPath && replyContext) try {
1242
+ if (!mediaPath && !mediaKind && replyContext?.media) try {
1225
1243
  await saveInboundMedia(await downloadQuotedInboundMedia(msg, sock, maxBytes));
1244
+ mediaKind = replyContext.media.kind ?? void 0;
1245
+ mediaType = mediaType ?? replyContext.media.contentType ?? void 0;
1226
1246
  } catch (err) {
1227
1247
  logWhatsAppVerbose(options.verbose, `Quoted media download failed: ${String(err)}`);
1228
1248
  body = formatInboundMediaUnavailableText({
@@ -1239,7 +1259,9 @@ async function attachWebInboxToSocket(options) {
1239
1259
  replyContext,
1240
1260
  mediaPath,
1241
1261
  mediaType,
1242
- mediaFileName
1262
+ mediaFileName,
1263
+ mediaKind,
1264
+ nativeMedia
1243
1265
  };
1244
1266
  };
1245
1267
  const enqueueInboundMessage = async (msg, inbound, enriched, durable) => {
@@ -1274,10 +1296,11 @@ async function attachWebInboxToSocket(options) {
1274
1296
  mediaFileName: enriched.mediaFileName,
1275
1297
  timestamp
1276
1298
  }, "inbound message");
1277
- const media = enriched.mediaPath || enriched.mediaType || enriched.mediaFileName ? {
1299
+ const media = enriched.mediaPath || enriched.mediaType || enriched.mediaFileName || enriched.mediaKind ? {
1278
1300
  path: enriched.mediaPath,
1279
1301
  type: enriched.mediaType,
1280
- fileName: enriched.mediaFileName
1302
+ fileName: enriched.mediaFileName,
1303
+ kind: enriched.mediaKind
1281
1304
  } : void 0;
1282
1305
  const groupMentions = mentionedJids ? { jids: mentionedJids } : void 0;
1283
1306
  const group = inbound.group && (inbound.groupSubject || inbound.groupParticipants?.length || groupMentions) ? {
@@ -1285,17 +1308,26 @@ async function attachWebInboxToSocket(options) {
1285
1308
  participants: inbound.groupParticipants,
1286
1309
  mentions: groupMentions
1287
1310
  } : void 0;
1288
- const untrustedStructuredContext = [...enriched.contactContext ? [{
1289
- label: "WhatsApp contact",
1290
- source: "whatsapp",
1291
- type: enriched.contactContext.kind,
1292
- payload: enriched.contactContext
1293
- }] : [], ...enriched.externalAdReplyContext ? [{
1294
- label: "WhatsApp external ad reply",
1295
- source: "whatsapp",
1296
- type: "external_ad_reply",
1297
- payload: enriched.externalAdReplyContext
1298
- }] : []];
1311
+ const untrustedStructuredContext = [
1312
+ ...enriched.nativeMedia ? [{
1313
+ label: "WhatsApp media",
1314
+ source: "whatsapp",
1315
+ type: "media",
1316
+ payload: enriched.nativeMedia
1317
+ }] : [],
1318
+ ...enriched.contactContext ? [{
1319
+ label: "WhatsApp contact",
1320
+ source: "whatsapp",
1321
+ type: enriched.contactContext.kind,
1322
+ payload: enriched.contactContext
1323
+ }] : [],
1324
+ ...enriched.externalAdReplyContext ? [{
1325
+ label: "WhatsApp external ad reply",
1326
+ source: "whatsapp",
1327
+ type: "external_ad_reply",
1328
+ payload: enriched.externalAdReplyContext
1329
+ }] : []
1330
+ ];
1299
1331
  const inboundMessage = withDeprecatedWebInboundMessageFlatAliases({
1300
1332
  admission: inbound.access.admission,
1301
1333
  event: {
@@ -1334,6 +1366,7 @@ async function attachWebInboxToSocket(options) {
1334
1366
  context: enriched.replyContext,
1335
1367
  id: enriched.replyContext.id,
1336
1368
  body: enriched.replyContext.body,
1369
+ media: enriched.replyContext.media,
1337
1370
  sender: {
1338
1371
  displayName: enriched.replyContext.sender?.label ?? void 0,
1339
1372
  jid: enriched.replyContext.sender?.jid ?? void 0,
@@ -1360,12 +1393,13 @@ async function attachWebInboxToSocket(options) {
1360
1393
  participant: inboundMessage.platform.senderJid,
1361
1394
  participantE164: admission.conversation.kind === "direct" ? inboundMessage.platform.senderE164 : void 0,
1362
1395
  body: inboundMessage.payload.body,
1396
+ media: enriched.nativeMedia,
1363
1397
  fromMe: inboundMessage.platform.fromMe
1364
1398
  });
1365
1399
  }
1366
1400
  await debouncer.enqueue(inboundMessage);
1367
1401
  };
1368
- const processWhatsAppInboundMessage = async (msg, context) => {
1402
+ const processDurableInboundMessage = async (msg, context) => {
1369
1403
  rememberBaileysMessage(msg.key?.remoteJid, msg.key?.id, msg.message);
1370
1404
  if (context.skipRecentOutboundEcho === true) return "completed";
1371
1405
  const preparation = context.eventId ? preparedInboundByDurableId.get(context.eventId) : void 0;
@@ -1401,81 +1435,28 @@ async function attachWebInboxToSocket(options) {
1401
1435
  });
1402
1436
  return "deferred";
1403
1437
  };
1404
- let durableDrainPass;
1405
- let durableDrainRequested = false;
1406
- let durableDrainClosed = false;
1407
- const requestDurableInboundDrain = () => {
1408
- if (durableDrainClosed) return Promise.resolve();
1409
- durableDrainRequested = true;
1410
- if (!durableDrainPass) {
1411
- let passFailed = false;
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);
1427
- 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
- }
1456
- });
1457
- const durableInboundDrain = createWhatsAppIngressDrain({
1438
+ const durableInboundMonitor = createWhatsAppIngressMonitor({
1458
1439
  queue: durableInboundQueue,
1459
1440
  dispatch: async (msg, payload, lifecycle) => {
1460
1441
  const remoteJid = msg.key?.remoteJid;
1461
1442
  const id = msg.key?.id;
1462
- return { kind: await processWhatsAppInboundMessage(msg, {
1443
+ return { kind: await processDurableInboundMessage(msg, {
1463
1444
  ...payload,
1464
1445
  ...remoteJid && id ? { eventId: createWhatsAppDurableInboundMessageId({
1465
1446
  remoteJid,
1466
1447
  id
1467
1448
  }) } : {},
1468
- lifecycle: continueDrainAfterLaneSettlement(lifecycle)
1449
+ lifecycle
1469
1450
  }) };
1470
1451
  },
1471
- onLog: (message) => inboundLogger.warn({ message }, "whatsapp ingress drain")
1452
+ pollIntervalMs: WHATSAPP_INGRESS_DRAIN_INTERVAL_MS,
1453
+ onLog: (message) => inboundLogger.warn({ message }, "whatsapp ingress drain"),
1454
+ onError: (error) => inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed"),
1455
+ onActivityChange: (active) => {
1456
+ durableIngressActive = active;
1457
+ publishPendingWorkState();
1458
+ }
1472
1459
  });
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
1460
  const handleMessagesUpsert = async (upsert) => {
1480
1461
  if (upsert.type !== "notify" && upsert.type !== "append") return;
1481
1462
  for (const msg of upsert.messages ?? []) {
@@ -1559,9 +1540,7 @@ async function attachWebInboxToSocket(options) {
1559
1540
  throw error;
1560
1541
  }
1561
1542
  else finishPreparation(void 0);
1562
- requestDurableInboundDrain().catch((error) => {
1563
- inboundLogger.error({ error: formatError(error) }, "whatsapp durable inbound drain failed");
1564
- });
1543
+ durableInboundMonitor.requestDrain();
1565
1544
  }
1566
1545
  }
1567
1546
  };
@@ -1588,7 +1567,6 @@ async function attachWebInboxToSocket(options) {
1588
1567
  };
1589
1568
  const drainInboundBeforeSocketClose = async () => {
1590
1569
  groupMetadataCacheClosed = true;
1591
- clearInterval(durableDrainTimer);
1592
1570
  for (;;) {
1593
1571
  await drainDebouncedInboundMessages();
1594
1572
  if (pendingMessageHandlers.size === 0) break;
@@ -1597,12 +1575,12 @@ async function attachWebInboxToSocket(options) {
1597
1575
  if (pendingMessageHandlers.size === 0 && pendingDebounceKeys.size === 0 && activeInboundFlushes.size === 0) break;
1598
1576
  }
1599
1577
  await drainDebouncedInboundMessages();
1600
- try {
1601
- await durableInboundDrain.waitForIdle();
1602
- } finally {
1603
- durableDrainClosed = true;
1604
- durableInboundDrain.dispose();
1578
+ for (;;) {
1579
+ await durableInboundMonitor.waitForIdle();
1580
+ if (pendingDebounceKeys.size === 0 && activeInboundFlushes.size === 0) break;
1581
+ await drainDebouncedInboundMessages();
1605
1582
  }
1583
+ await durableInboundMonitor.stop();
1606
1584
  };
1607
1585
  const drainInboundBeforeSocketCloseWithTimeout = async () => {
1608
1586
  let timeout = null;
@@ -1615,8 +1593,7 @@ async function attachWebInboxToSocket(options) {
1615
1593
  })]);
1616
1594
  } finally {
1617
1595
  if (timeout) clearTimeout(timeout);
1618
- durableDrainClosed = true;
1619
- durableInboundDrain.dispose();
1596
+ durableInboundMonitor.stop();
1620
1597
  }
1621
1598
  };
1622
1599
  const handleConnectionUpdate = (update) => {
@@ -1675,10 +1652,7 @@ async function attachWebInboxToSocket(options) {
1675
1652
  const detachGroupParticipantsUpdate = attachSockListener("group-participants.update", ((update) => {
1676
1653
  forgetFullGroupMetadata(update.id);
1677
1654
  }));
1678
- requestDurableInboundDrain().catch((err) => {
1679
- inboundLogger.error({ error: String(err) }, "failed replaying durable WhatsApp inbound");
1680
- inboundConsoleLog.error(`Failed replaying durable WhatsApp inbound: ${String(err)}`);
1681
- });
1655
+ durableInboundMonitor.start();
1682
1656
  (async () => {
1683
1657
  try {
1684
1658
  const groups = await sock.groupFetchAllParticipating();
@@ -1736,7 +1710,7 @@ async function attachWebInboxToSocket(options) {
1736
1710
  };
1737
1711
  }
1738
1712
  async function monitorWebInbox(options) {
1739
- const socketTiming = options.socketTiming ?? resolveWhatsAppSocketTiming(options.cfg);
1713
+ const socketTiming = options.socketTiming ?? resolveWhatsAppSocketTiming();
1740
1714
  const recentMessageKeys = options.recentMessageKeys ?? /* @__PURE__ */ new Map();
1741
1715
  const baileysGroupMetaCache = options.baileysGroupMetaCache ?? /* @__PURE__ */ new Map();
1742
1716
  const sock = await createWaSocket(false, options.verbose, {
@@ -1794,12 +1768,13 @@ function isBotMentionedFromTargets(msg, mentionCfg, targets) {
1794
1768
  const isGroupConversation = requireWhatsAppInboundAdmission(msg).conversation.kind === "group";
1795
1769
  const isSelfChat = explicitSelfChatOverride ? Boolean(mentionCfg.isSelfChat) : isSelfChatMode(targets.self.e164, mentionCfg.allowFrom) && !isGroupConversation;
1796
1770
  const hasMentions = targets.normalizedMentions.length > 0;
1797
- if (hasMentions && !isSelfChat) {
1771
+ const hasNativeMentionsOutsideSelfChat = hasMentions && !isSelfChat;
1772
+ if (hasNativeMentionsOutsideSelfChat) {
1798
1773
  for (const mention of targets.normalizedMentions) if (identitiesOverlap(targets.self, mention)) return true;
1799
- return false;
1800
1774
  } else if (hasMentions && isSelfChat) {}
1801
1775
  const bodyClean = clean(msg.payload.body);
1802
1776
  if (mentionCfg.mentionRegexes.some((re) => re.test(bodyClean))) return true;
1777
+ if (hasNativeMentionsOutsideSelfChat) return false;
1803
1778
  if (targets.self.e164) {
1804
1779
  const selfDigits = targets.self.e164.replace(/\D/g, "");
1805
1780
  if (selfDigits) {
@@ -1980,8 +1955,7 @@ function formatWhatsAppInboundListeningLog(account) {
1980
1955
  const DEFAULT_WHATSAPP_ACK_REACTION = "👀";
1981
1956
  function resolveWhatsAppAckEmoji(params) {
1982
1957
  if (!params.ackConfig) return "";
1983
- if (params.ackConfig.emoji !== void 0) return params.ackConfig.emoji.trim();
1984
- return resolveAgentIdentityEmoji(params.cfg, params.agentId) ?? DEFAULT_WHATSAPP_ACK_REACTION;
1958
+ return (typeof params.ackConfig === "string" ? params.ackConfig : params.ackConfig.emoji)?.trim() || resolveAgentIdentityEmoji(params.cfg, params.agentId) || DEFAULT_WHATSAPP_ACK_REACTION;
1985
1959
  }
1986
1960
  function resolveAgentIdentityEmoji(cfg, agentId) {
1987
1961
  return resolveAgentIdentity(cfg, agentId)?.emoji?.trim() || void 0;
@@ -2034,6 +2008,12 @@ async function resolveGroupActivationFor(params) {
2034
2008
  return normalizeGroupActivation(activation) ?? defaultActivation;
2035
2009
  }
2036
2010
  //#endregion
2011
+ //#region extensions/whatsapp/src/auto-reply/monitor/reaction-participant.ts
2012
+ function resolveReactionParticipant(msg) {
2013
+ const sender = getSenderIdentity(msg);
2014
+ return sender.jid ?? sender.lid ?? void 0;
2015
+ }
2016
+ //#endregion
2037
2017
  //#region extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts
2038
2018
  async function maybeSendAckReaction(params) {
2039
2019
  if (!params.msg.event.id) return null;
@@ -2043,14 +2023,16 @@ async function maybeSendAckReaction(params) {
2043
2023
  cfg: params.cfg,
2044
2024
  accountId
2045
2025
  }).level === "off") return null;
2046
- const ackConfig = params.cfg.channels?.whatsapp?.ackReaction;
2026
+ const ackConfig = params.cfg.messages?.ackReaction;
2027
+ const scope = params.cfg.messages?.ackReactionScope ?? "group-mentions";
2028
+ if (scope === "off" || scope === "none") return null;
2047
2029
  const emoji = resolveWhatsAppAckEmoji({
2048
2030
  cfg: params.cfg,
2049
2031
  agentId: params.agentId,
2050
2032
  ackConfig
2051
2033
  });
2052
- const directEnabled = ackConfig?.direct ?? true;
2053
- const groupMode = ackConfig?.group ?? "mentions";
2034
+ const directEnabled = scope === "all" || scope === "direct";
2035
+ const groupMode = scope === "all" || scope === "group-all" ? "always" : scope === "direct" ? "never" : "mentions";
2054
2036
  const isGroup = admission.conversation.kind === "group";
2055
2037
  const conversationIdForCheck = admission.conversation.id;
2056
2038
  const activation = isGroup ? await resolveGroupActivationFor({
@@ -2075,11 +2057,11 @@ async function maybeSendAckReaction(params) {
2075
2057
  messageId: params.msg.event.id,
2076
2058
  emoji
2077
2059
  }, "sending ack reaction");
2078
- const sender = getSenderIdentity(params.msg);
2060
+ const participant = resolveReactionParticipant(params.msg);
2079
2061
  const reactionOptions = {
2080
2062
  verbose: params.verbose,
2081
2063
  fromMe: false,
2082
- ...sender.jid ? { participant: sender.jid } : {},
2064
+ ...participant ? { participant } : {},
2083
2065
  accountId,
2084
2066
  cfg: params.cfg
2085
2067
  };
@@ -2249,7 +2231,13 @@ function recordPendingGroupHistoryEntry(params) {
2249
2231
  body: params.body ?? params.msg.payload.body,
2250
2232
  timestamp: params.msg.event.timestamp,
2251
2233
  id: params.msg.event.id,
2252
- senderJid: senderIdentity.jid ?? params.msg.platform.senderJid
2234
+ senderJid: senderIdentity.jid ?? params.msg.platform.senderJid,
2235
+ ...params.body === void 0 && params.msg.payload.media ? { media: [{
2236
+ path: params.msg.payload.media.path,
2237
+ url: params.msg.payload.media.url ?? params.msg.payload.media.path,
2238
+ contentType: params.msg.payload.media.type,
2239
+ kind: params.msg.payload.media.kind ?? void 0
2240
+ }] } : {}
2253
2241
  }
2254
2242
  });
2255
2243
  }
@@ -2585,7 +2573,7 @@ async function deliverWebReply(params) {
2585
2573
  const tableMode = params.tableMode ?? "code";
2586
2574
  const chunkMode = params.chunkMode ?? "length";
2587
2575
  const normalizedReply = params.normalizedReplyResult ?? normalizeWhatsAppOutboundPayload(replyResult, { normalizeText: normalizeWhatsAppPayloadTextPreservingIndentation });
2588
- const textChunks = chunkMarkdownTextWithMode(markdownToWhatsApp(convertMarkdownTables$1(normalizedReply.text ?? "", tableMode)), textLimit, chunkMode);
2576
+ const textChunks = markdownToWhatsAppChunks(normalizedReply.text ?? "", textLimit, tableMode, chunkMode);
2589
2577
  const mediaList = normalizedReply.mediaUrls ?? [];
2590
2578
  const getQuote = () => {
2591
2579
  if (!replyResult.replyToId) return;
@@ -2595,7 +2583,8 @@ async function deliverWebReply(params) {
2595
2583
  remoteJid: msg.platform.chatJid,
2596
2584
  fromMe: cached?.fromMe ?? false,
2597
2585
  participant: cached?.participant ?? (isGroupConversation ? msg.platform.senderJid : void 0),
2598
- messageText: cached?.body ?? ""
2586
+ messageText: cached?.body ?? "",
2587
+ media: cached?.media
2599
2588
  });
2600
2589
  };
2601
2590
  const sendWithRetry = async (fn, label) => {
@@ -2643,7 +2632,7 @@ async function deliverWebReply(params) {
2643
2632
  mediaUrls: mediaList,
2644
2633
  caption: remainingText.shift() || "",
2645
2634
  send: async ({ mediaUrl, caption }) => {
2646
- const media = await prepareWhatsAppOutboundMedia(await loadWebMedia$1(mediaUrl, {
2635
+ const media = await prepareWhatsAppOutboundMedia(await loadWebMedia(mediaUrl, {
2647
2636
  maxBytes: maxMediaBytes,
2648
2637
  localRoots: params.mediaLocalRoots
2649
2638
  }), mediaUrl);
@@ -2749,8 +2738,10 @@ function resolveVisibleWhatsAppGroupHistory(params) {
2749
2738
  function resolveVisibleWhatsAppReplyContext(params) {
2750
2739
  const replyTo = getReplyContext(params.msg, params.authDir);
2751
2740
  if (!replyTo) return null;
2741
+ const admission = requireWhatsAppInboundAdmission(params.msg);
2742
+ const previewBody = [replyTo.body, formatMediaPlaceholderText(replyTo.media ? [replyTo.media] : [])].filter(Boolean).join("\n");
2752
2743
  const senderAllowed = resolveInboundSupplementalSenderAllowed({
2753
- isGroup: requireWhatsAppInboundAdmission(params.msg).conversation.kind === "group",
2744
+ isGroup: admission.conversation.kind === "group",
2754
2745
  groupPolicy: params.groupPolicy,
2755
2746
  allowFrom: params.groupAllowFrom,
2756
2747
  isSenderAllowed: (allowFrom) => isWhatsAppSupplementalSenderAllowed({
@@ -2759,12 +2750,16 @@ function resolveVisibleWhatsAppReplyContext(params) {
2759
2750
  sender: replyTo.sender
2760
2751
  })
2761
2752
  });
2762
- return filterChannelInboundQuoteContext(params.mode, {
2753
+ const visible = filterChannelInboundQuoteContext(params.mode, {
2763
2754
  id: replyTo.id,
2764
- body: replyTo.body,
2755
+ body: previewBody,
2765
2756
  sender: replyTo.sender?.label ?? void 0,
2766
2757
  senderAllowed
2767
- }) ? replyTo : null;
2758
+ });
2759
+ return visible ? {
2760
+ ...replyTo,
2761
+ body: visible.body ?? ""
2762
+ } : null;
2768
2763
  }
2769
2764
  //#endregion
2770
2765
  //#region extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts
@@ -2873,7 +2868,7 @@ function logWhatsAppMediaOnlyFlushResult(result) {
2873
2868
  }
2874
2869
  function resolveWhatsAppResponsePrefix(params) {
2875
2870
  const configuredResponsePrefix = params.cfg.messages?.responsePrefix;
2876
- return params.pipelineResponsePrefix ?? (configuredResponsePrefix === void 0 && params.isSelfChat ? resolveIdentityNamePrefix$1(params.cfg, params.agentId) : void 0);
2871
+ return params.pipelineResponsePrefix ?? (configuredResponsePrefix === "auto" ? resolveIdentityNamePrefix$1(params.cfg, params.agentId) : configuredResponsePrefix) ?? (params.isSelfChat ? resolveIdentityNamePrefix$1(params.cfg, params.agentId) : void 0);
2877
2872
  }
2878
2873
  async function buildWhatsAppInboundContext(params) {
2879
2874
  const admission = requireWhatsAppInboundAdmission(params.msg);
@@ -2885,14 +2880,16 @@ async function buildWhatsAppInboundContext(params) {
2885
2880
  sender: entry.sender,
2886
2881
  body: entry.body,
2887
2882
  timestamp: entry.timestamp,
2888
- messageId: entry.id
2883
+ messageId: entry.id,
2884
+ media: entry.media
2889
2885
  })),
2890
2886
  limit: params.groupHistory?.length ?? 1
2891
2887
  }) : void 0;
2892
- const media = toInboundMediaFacts(params.msg.payload.media?.path || params.msg.payload.media?.url ? [{
2888
+ const media = toInboundMediaFacts(params.msg.payload.media ? [{
2893
2889
  path: params.msg.payload.media?.path,
2894
2890
  url: params.msg.payload.media?.url ?? params.msg.payload.media?.path,
2895
- contentType: params.msg.payload.media?.type
2891
+ contentType: params.msg.payload.media?.type,
2892
+ kind: params.msg.payload.media?.kind
2896
2893
  }] : void 0, { transcribed: (_entry, index) => params.mediaTranscribedIndexes?.includes(index) === true });
2897
2894
  return buildChannelInboundEventContext({
2898
2895
  channel: "whatsapp",
@@ -2935,6 +2932,7 @@ async function buildWhatsAppInboundContext(params) {
2935
2932
  rawBody: params.rawBody ?? params.msg.payload.body,
2936
2933
  commandBody: params.command?.body ?? params.msg.payload.body
2937
2934
  },
2935
+ sessionTranscript: { historyLimit: conversationKind === "group" ? params.groupHistoryLimit ?? params.groupHistory?.length ?? 0 : 0 },
2938
2936
  access: {
2939
2937
  ...wasMentioned !== void 0 ? { mentions: {
2940
2938
  canDetectMention: conversationKind === "group",
@@ -2995,11 +2993,6 @@ function createWhatsAppReplyPlan(params) {
2995
2993
  const conversationId = admission.conversation.id;
2996
2994
  const conversationKind = admission.conversation.kind;
2997
2995
  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
2996
  const textLimit = params.maxMediaTextChunkLimit ?? resolveTextChunkLimit(params.cfg, "whatsapp");
3004
2997
  const chunkMode = resolveChunkMode(params.cfg, "whatsapp", params.route.accountId);
3005
2998
  const tableMode = resolveMarkdownTableMode$1({
@@ -3192,10 +3185,7 @@ function createWhatsAppReplyPlan(params) {
3192
3185
  if (!didQueueVisibleReply) {
3193
3186
  if (statusReactionController) finalizeWhatsAppStatusReaction({
3194
3187
  controller: statusReactionController,
3195
- outcome: "error",
3196
- hasFinalResponse: false,
3197
- removeAckAfterReply,
3198
- timing: statusReactionTiming
3188
+ outcome: "error"
3199
3189
  });
3200
3190
  if (params.shouldClearGroupHistory) params.groupHistories.set(params.groupHistoryKey, []);
3201
3191
  logVerbose$1("Skipping auto-reply: silent token or no text/media returned from resolver");
@@ -3203,10 +3193,7 @@ function createWhatsAppReplyPlan(params) {
3203
3193
  }
3204
3194
  if (statusReactionController) finalizeWhatsAppStatusReaction({
3205
3195
  controller: statusReactionController,
3206
- outcome: didDeliverVisibleReply ? "done" : "error",
3207
- hasFinalResponse: didDeliverVisibleReply,
3208
- removeAckAfterReply,
3209
- timing: statusReactionTiming
3196
+ outcome: didDeliverVisibleReply ? "done" : "error"
3210
3197
  });
3211
3198
  if (params.shouldClearGroupHistory) params.groupHistories.set(params.groupHistoryKey, []);
3212
3199
  return didDeliverVisibleReply;
@@ -3214,29 +3201,8 @@ function createWhatsAppReplyPlan(params) {
3214
3201
  };
3215
3202
  }
3216
3203
  async function finalizeWhatsAppStatusReaction(params) {
3217
- if (params.outcome === "done") {
3218
- await params.controller.setDone();
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
- });
3204
+ if (params.outcome === "done") await params.controller.setDone();
3205
+ else await params.controller.setError();
3240
3206
  await params.controller.restoreInitial();
3241
3207
  }
3242
3208
  //#endregion
@@ -3250,7 +3216,7 @@ function resolveIdentityNamePrefix(cfg, agentId) {
3250
3216
  return identityName ? `[${identityName}]` : void 0;
3251
3217
  }
3252
3218
  function resolveMessagePrefix(cfg, agentId, opts) {
3253
- const configured = opts?.configured ?? cfg.messages?.messagePrefix;
3219
+ const configured = opts?.configured;
3254
3220
  if (configured !== void 0) return configured;
3255
3221
  if (opts?.hasAllowFrom === true) return "";
3256
3222
  return resolveIdentityNamePrefix(cfg, agentId) ?? opts?.fallback ?? "[openclaw]";
@@ -3267,7 +3233,7 @@ function formatReplyContext(msg) {
3267
3233
  function buildInboundLine(params) {
3268
3234
  const { cfg, msg, agentId, previousTimestamp, envelope } = params;
3269
3235
  const messagePrefix = resolveMessagePrefix(cfg, agentId, {
3270
- configured: cfg.channels?.whatsapp?.messagePrefix,
3236
+ configured: cfg.channels?.whatsapp?.responsePrefix,
3271
3237
  hasAllowFrom: (cfg.channels?.whatsapp?.allowFrom?.length ?? 0) > 0
3272
3238
  });
3273
3239
  const admission = requireWhatsAppInboundAdmission(msg);
@@ -3297,23 +3263,24 @@ function buildInboundLine(params) {
3297
3263
  //#region extensions/whatsapp/src/auto-reply/monitor/status-reaction.ts
3298
3264
  async function createWhatsAppStatusReactionController(params) {
3299
3265
  if (!params.msg.event.id) return null;
3300
- const statusReactionsConfig = params.cfg.messages?.statusReactions;
3301
- if (statusReactionsConfig?.enabled !== true) return null;
3266
+ if ((params.cfg.messages?.statusReactions)?.enabled !== true) return null;
3302
3267
  const admission = requireWhatsAppInboundAdmission(params.msg);
3303
3268
  const accountId = admission.accountId;
3304
3269
  if (resolveWhatsAppReactionLevel({
3305
3270
  cfg: params.cfg,
3306
3271
  accountId
3307
3272
  }).level === "off") return null;
3308
- const ackConfig = params.cfg.channels?.whatsapp?.ackReaction;
3273
+ const ackConfig = params.cfg.messages?.ackReaction;
3274
+ const scope = params.cfg.messages?.ackReactionScope ?? "group-mentions";
3275
+ if (scope === "off" || scope === "none") return null;
3309
3276
  const ackEmoji = resolveWhatsAppAckEmoji({
3310
3277
  cfg: params.cfg,
3311
3278
  agentId: params.agentId,
3312
3279
  ackConfig
3313
3280
  });
3314
3281
  if (!ackEmoji) return null;
3315
- const directEnabled = ackConfig?.direct ?? true;
3316
- const groupMode = ackConfig?.group ?? "mentions";
3282
+ const directEnabled = scope === "all" || scope === "direct";
3283
+ const groupMode = scope === "all" || scope === "group-all" ? "always" : scope === "direct" ? "never" : "mentions";
3317
3284
  const isGroup = admission.conversation.kind === "group";
3318
3285
  const conversationIdForCheck = admission.conversation.id;
3319
3286
  const activation = isGroup ? await resolveGroupActivationFor({
@@ -3332,11 +3299,11 @@ async function createWhatsAppStatusReactionController(params) {
3332
3299
  wasMentioned: (params.msg.groupMention?.wasMentioned ?? params.msg.wasMentioned) === true,
3333
3300
  groupActivated: activation === "always"
3334
3301
  })) return null;
3335
- const sender = getSenderIdentity(params.msg);
3302
+ const participant = resolveReactionParticipant(params.msg);
3336
3303
  const reactionOptions = {
3337
3304
  verbose: params.verbose,
3338
3305
  fromMe: false,
3339
- ...sender.jid ? { participant: sender.jid } : {},
3306
+ ...participant ? { participant } : {},
3340
3307
  accountId,
3341
3308
  cfg: params.cfg
3342
3309
  };
@@ -3353,8 +3320,7 @@ async function createWhatsAppStatusReactionController(params) {
3353
3320
  }
3354
3321
  },
3355
3322
  initialEmoji: ackEmoji,
3356
- emojis: statusReactionsConfig.emojis,
3357
- timing: statusReactionsConfig.timing,
3323
+ emojis: void 0,
3358
3324
  onError: (err) => {
3359
3325
  logVerbose(`WhatsApp status-reaction error for chat ${chatId}/${msgId}: ${String(err)}`);
3360
3326
  }
@@ -3423,13 +3389,16 @@ async function processMessage(params) {
3423
3389
  sessionKey: params.route.sessionKey
3424
3390
  });
3425
3391
  let audioTranscript = params.preflightAudioTranscript ?? void 0;
3426
- const hasAudioBody = params.msg.payload.media?.type?.startsWith("audio/") === true && params.msg.payload.body === "<media:audio>";
3392
+ const hasAudioBody = (params.msg.payload.media?.kind === "audio" || params.msg.payload.media?.type?.startsWith("audio/") === true) && !params.msg.payload.body.trim();
3427
3393
  if (params.preflightAudioTranscript === void 0 && hasAudioBody && params.msg.payload.media?.path) try {
3428
3394
  const { transcribeFirstAudio } = await import("./audio-preflight.runtime-C_glQhZY.js");
3429
3395
  audioTranscript = await transcribeFirstAudio({
3430
3396
  ctx: {
3431
- MediaPaths: [params.msg.payload.media?.path],
3432
- MediaTypes: params.msg.payload.media?.type ? [params.msg.payload.media?.type] : void 0,
3397
+ media: [{
3398
+ path: params.msg.payload.media.path,
3399
+ contentType: params.msg.payload.media.type,
3400
+ kind: params.msg.payload.media.kind ?? void 0
3401
+ }],
3433
3402
  From: conversationId,
3434
3403
  To: params.msg.platform.recipientJid,
3435
3404
  Provider: "whatsapp",
@@ -3441,7 +3410,7 @@ async function processMessage(params) {
3441
3410
  cfg: params.cfg
3442
3411
  });
3443
3412
  } catch {
3444
- if (shouldLogVerbose$1()) logVerbose$1("whatsapp: audio preflight transcription failed, using placeholder");
3413
+ if (shouldLogVerbose$1()) logVerbose$1("whatsapp: audio preflight transcription failed, keeping structured audio");
3445
3414
  }
3446
3415
  const msgForAgent = audioTranscript !== void 0 ? {
3447
3416
  ...params.msg,
@@ -3479,7 +3448,8 @@ async function processMessage(params) {
3479
3448
  entries: history.map((m) => ({
3480
3449
  sender: m.sender,
3481
3450
  body: m.body,
3482
- timestamp: m.timestamp
3451
+ timestamp: m.timestamp,
3452
+ media: m.media
3483
3453
  })),
3484
3454
  currentMessage: combinedBody,
3485
3455
  excludeLast: false,
@@ -3488,7 +3458,7 @@ async function processMessage(params) {
3488
3458
  channel: "WhatsApp",
3489
3459
  from: conversationId,
3490
3460
  timestamp: entry.timestamp,
3491
- body: entry.body,
3461
+ body: [entry.body, formatMediaPlaceholderText(entry.media ?? [])].filter(Boolean).join("\n"),
3492
3462
  chatType: "group",
3493
3463
  senderLabel: entry.sender,
3494
3464
  envelope: envelopeOptions
@@ -3582,6 +3552,7 @@ async function processMessage(params) {
3582
3552
  authorized: commandAuthorized
3583
3553
  },
3584
3554
  groupHistory: visibleGroupHistory,
3555
+ groupHistoryLimit: params.groupHistoryLimit,
3585
3556
  groupMemberRoster: params.groupMemberNames.get(params.groupHistoryKey),
3586
3557
  groupSystemPrompt: conversationSystemPrompt,
3587
3558
  msg: params.msg,
@@ -3704,7 +3675,7 @@ async function processMessage(params) {
3704
3675
  });
3705
3676
  const didSendReply = turnResult.dispatched ? finalizeReply?.(turnResult.dispatchResult) ?? false : false;
3706
3677
  removeAckReactionHandleAfterReply({
3707
- removeAfterReply: Boolean(params.cfg.messages?.removeAckAfterReply && didSendReply),
3678
+ removeAfterReply: false,
3708
3679
  ackReaction,
3709
3680
  onError: (err) => {
3710
3681
  logAckFailure({
@@ -3744,6 +3715,7 @@ function createWebOnMessageHandler(params) {
3744
3715
  route,
3745
3716
  groupHistoryKey,
3746
3717
  groupHistories: params.groupHistories,
3718
+ groupHistoryLimit: params.groupHistoryLimit,
3747
3719
  groupMemberNames: params.groupMemberNames,
3748
3720
  connectionId: params.connectionId,
3749
3721
  verbose: params.verbose,
@@ -3811,7 +3783,7 @@ function createWebOnMessageHandler(params) {
3811
3783
  peerId
3812
3784
  }) : route.sessionKey;
3813
3785
  let preflightAudioTranscript;
3814
- const hasAudioBody = msg.payload.media?.type?.startsWith("audio/") === true && msg.payload.body === "<media:audio>";
3786
+ const hasAudioBody = (msg.payload.media?.kind === "audio" || msg.payload.media?.type?.startsWith("audio/") === true) && !msg.payload.body.trim();
3815
3787
  const canRunEarlyAudioPreflight = conversationKind === "group" || canRunDirectEarlyAudioPreflight;
3816
3788
  let ackAlreadySent = false;
3817
3789
  let ackReaction = null;
@@ -3837,8 +3809,11 @@ function createWebOnMessageHandler(params) {
3837
3809
  const { transcribeFirstAudio } = await import("./audio-preflight.runtime-C_glQhZY.js");
3838
3810
  preflightAudioTranscript = await transcribeFirstAudio({
3839
3811
  ctx: {
3840
- MediaPaths: [msg.payload.media?.path],
3841
- MediaTypes: msg.payload.media?.type ? [msg.payload.media?.type] : void 0,
3812
+ media: [{
3813
+ path: msg.payload.media.path,
3814
+ contentType: msg.payload.media.type,
3815
+ kind: msg.payload.media.kind ?? void 0
3816
+ }],
3842
3817
  From: conversationId,
3843
3818
  To: msg.platform.recipientJid,
3844
3819
  Provider: "whatsapp",
@@ -4009,8 +3984,7 @@ function resolveWebMonitorConfigSnapshot(params) {
4009
3984
  ...params.cfg.channels,
4010
3985
  whatsapp: {
4011
3986
  ...params.cfg.channels?.whatsapp,
4012
- ackReaction: account.ackReaction,
4013
- messagePrefix: account.messagePrefix,
3987
+ responsePrefix: account.messagePrefix,
4014
3988
  allowFrom: account.allowFrom,
4015
3989
  groupAllowFrom: account.groupAllowFrom,
4016
3990
  groupPolicy: account.groupPolicy,
@@ -4075,7 +4049,7 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
4075
4049
  const maxMediaBytes = resolveWhatsAppMediaMaxBytes(account);
4076
4050
  const heartbeatSeconds = resolveHeartbeatSeconds(cfg, tuning.heartbeatSeconds);
4077
4051
  const reconnectPolicy = resolveReconnectPolicy(cfg, tuning.reconnect);
4078
- const socketTiming = resolveWhatsAppSocketTiming(cfg, tuning.socketTiming);
4052
+ const socketTiming = resolveWhatsAppSocketTiming(tuning.socketTiming);
4079
4053
  const baseMentionConfig = buildMentionConfig(cfg);
4080
4054
  const groupHistoryLimit = account.historyLimit ?? cfg.channels?.whatsapp?.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT;
4081
4055
  const groupHistories = /* @__PURE__ */ new Map();
@@ -4474,4 +4448,4 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
4474
4448
  }
4475
4449
  }
4476
4450
  //#endregion
4477
- export { loadWebMediaRaw as a, monitorWebInbox as c, loadWebMedia$1 as i, resetWebInboundDedupe as l, LocalMediaAccessError as n, optimizeImageToJpeg as o, getDefaultLocalRoots as r, optimizeImageToPng as s, monitorWebChannel as t };
4451
+ 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 };