fix(whatsapp): ignore outbound echoes for inbound activity (#79057) · openclaw/openclaw@36f847a
ai-hpc
·
2026-05-08
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -598,6 +598,7 @@ Docs: https://docs.openclaw.ai
|
598 | 598 | - Hooks/cron: log returned `/hooks/agent` isolated-run errors and failed cron jobs with cron diagnostic summaries, so rejected `payload.model` values are visible instead of looking like accepted-but-missing runs. Fixes #78597. (#78655) Thanks @kevinslin. |
599 | 599 | - Managed proxy/security: classify raw socket callsites and proxy runtime mutations in boundary checks so new direct egress or unmanaged proxy-state changes cannot land without explicit review. (#77126) Thanks @jesse-merhi. |
600 | 600 | - Channels/iMessage: surface the silent group-allowlist drop at default log level by emitting a one-time `warn` per account at monitor startup when `channels.imessage.groupPolicy: "allowlist"` is set without a `channels.imessage.groups` block, plus a one-time `warn` per `chat_id` when the runtime gate drops a specific group, naming the exact `channels.imessage.groups[...]` key to add to allow it. Fixes #78749. (#79190) Thanks @omarshahine. |
| 601 | +- WhatsApp: stop Gateway-originated outbound echoes from advancing inbound activity in `openclaw channels status`, so outbound self-sends no longer look like handled inbound messages. Fixes #79056. (#79057) Thanks @ai-hpc and @bittoby. |
601 | 602 | |
602 | 603 | ## 2026.5.3-1 |
603 | 604 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -113,6 +113,14 @@ function isGroupJid(jid: string): boolean {
|
113 | 113 | return (typeof isJidGroup === "function" ? isJidGroup(jid) : jid.endsWith("@g.us")) === true; |
114 | 114 | } |
115 | 115 | |
| 116 | +function recordAcceptedInboundActivity(accountId: string): void { |
| 117 | +recordChannelActivity({ |
| 118 | +channel: "whatsapp", |
| 119 | + accountId, |
| 120 | +direction: "inbound", |
| 121 | +}); |
| 122 | +} |
| 123 | + |
116 | 124 | function isRetryableSendDisconnectError(err: unknown): boolean { |
117 | 125 | return /closed|reset|timed\s*out|disconnect|no active socket/i.test(formatError(err)); |
118 | 126 | } |
@@ -799,11 +807,6 @@ export async function attachWebInboxToSocket(
|
799 | 807 | return; |
800 | 808 | } |
801 | 809 | for (const msg of upsert.messages ?? []) { |
802 | | -recordChannelActivity({ |
803 | | -channel: "whatsapp", |
804 | | -accountId: options.accountId, |
805 | | -direction: "inbound", |
806 | | -}); |
807 | 810 | const inbound = await normalizeInboundMessage(msg); |
808 | 811 | if (!inbound) { |
809 | 812 | continue; |
@@ -832,6 +835,7 @@ export async function attachWebInboxToSocket(
|
832 | 835 | continue; |
833 | 836 | } |
834 | 837 | |
| 838 | +recordAcceptedInboundActivity(options.accountId); |
835 | 839 | await enqueueInboundMessage(msg, inbound, enriched); |
836 | 840 | } |
837 | 841 | }; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -3,6 +3,7 @@ import { describe, expect, it, vi } from "vitest";
|
3 | 3 | import { |
4 | 4 | buildNotifyMessageUpsert, |
5 | 5 | expectPairingPromptSent, |
| 6 | +getRecordChannelActivityMock, |
6 | 7 | installWebMonitorInboxUnitTestHooks, |
7 | 8 | mockLoadConfig, |
8 | 9 | settleInboundWork, |
@@ -33,6 +34,20 @@ async function openInboxMonitor(onMessage = vi.fn()) {
|
33 | 34 | return { onMessage, listener, sock }; |
34 | 35 | } |
35 | 36 | |
| 37 | +function expectOnlyOutboundChannelActivity(accountId = "default") { |
| 38 | +const recordChannelActivityMock = getRecordChannelActivityMock(); |
| 39 | +expect(recordChannelActivityMock).toHaveBeenCalledWith({ |
| 40 | +channel: "whatsapp", |
| 41 | + accountId, |
| 42 | +direction: "outbound", |
| 43 | +}); |
| 44 | +expect(recordChannelActivityMock).not.toHaveBeenCalledWith({ |
| 45 | +channel: "whatsapp", |
| 46 | + accountId, |
| 47 | +direction: "inbound", |
| 48 | +}); |
| 49 | +} |
| 50 | + |
36 | 51 | async function expectOutboundDmSkipsPairing(params: { |
37 | 52 | selfChatMode: boolean; |
38 | 53 | messageId: string; |
@@ -294,6 +309,7 @@ describe("web monitor inbox", () => {
|
294 | 309 | await settleInboundWork(); |
295 | 310 | |
296 | 311 | expect(onMessage).not.toHaveBeenCalled(); |
| 312 | +expectOnlyOutboundChannelActivity(); |
297 | 313 | |
298 | 314 | await listener.close(); |
299 | 315 | }); |
@@ -333,6 +349,7 @@ describe("web monitor inbox", () => {
|
333 | 349 | await settleInboundWork(); |
334 | 350 | |
335 | 351 | expect(onMessage).not.toHaveBeenCalled(); |
| 352 | +expectOnlyOutboundChannelActivity(); |
336 | 353 | |
337 | 354 | await listener.close(); |
338 | 355 | }); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -55,6 +55,25 @@ const sessionState = vi.hoisted(() => ({
|
55 | 55 | sock: undefined as MockSock | undefined, |
56 | 56 | })); |
57 | 57 | |
| 58 | +const channelActivityMocks = vi.hoisted(() => ({ |
| 59 | +recordChannelActivity: vi.fn(), |
| 60 | +})); |
| 61 | + |
| 62 | +export function getRecordChannelActivityMock(): AnyMockFn { |
| 63 | +return channelActivityMocks.recordChannelActivity; |
| 64 | +} |
| 65 | + |
| 66 | +vi.mock("openclaw/plugin-sdk/channel-activity-runtime", async () => { |
| 67 | +const actual = await vi.importActual< |
| 68 | +typeof import("openclaw/plugin-sdk/channel-activity-runtime") |
| 69 | +>("openclaw/plugin-sdk/channel-activity-runtime"); |
| 70 | +return { |
| 71 | + ...actual, |
| 72 | +recordChannelActivity: (...args: unknown[]) => |
| 73 | +channelActivityMocks.recordChannelActivity(...args), |
| 74 | +}; |
| 75 | +}); |
| 76 | + |
58 | 77 | const inboundRuntimeMocks = vi.hoisted(() => { |
59 | 78 | const wrapperKeys = [ |
60 | 79 | "ephemeralMessage", |
@@ -277,6 +296,7 @@ export function installWebMonitorInboxUnitTestHooks(opts?: { authDir?: boolean }
|
277 | 296 | beforeEach(async () => { |
278 | 297 | vi.useRealTimers(); |
279 | 298 | vi.clearAllMocks(); |
| 299 | +channelActivityMocks.recordChannelActivity.mockClear(); |
280 | 300 | sessionState.sock = createMockSock(); |
281 | 301 | resetPairingSecurityMocks(DEFAULT_WEB_INBOX_CONFIG); |
282 | 302 | if (!monitorWebInbox || !resetWebInboundDedupe) { |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。