fix(imessage): normalize leading echoed text corruption · openclaw/openclaw@be445dd
openclaw-clo
·
2026-04-29
·
via Recent Commits to openclaw:main
File tree
extensions/imessage/src/monitor
| Original file line number | Diff line number | Diff line change |
|---|
@@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai
|
20 | 20 | - Active Memory: register the prompt-build hook with the configured recall timeout plus setup grace instead of the 150s maximum budget, so default memory recall cannot delay turn startup for multiple minutes. Thanks @vincentkoc. |
21 | 21 | - CLI/channels logs: reuse the rolling log-file resolver so `openclaw channels logs` falls back to the active dated log across date boundaries without reading unrelated custom log files. Fixes #42875; carries forward #42904 and #43043. Thanks @ethanclaw and @wdskuki. |
22 | 22 | - CLI/update: skip tracked plugins disabled in config during post-update plugin sync before npm, ClawHub, or marketplace update checks, preserving their install records without failing the update. Fixes #73880. Thanks @islandpreneur007. |
| 23 | +- iMessage: normalize known leading attributedBody corruption markers on sent-message echo text keys so delayed reflected echoes with U+FFFD/U+FFFE/U+FFFF/FEFF prefixes are dropped without collapsing interior text. Fixes #59973; carries forward #59980 and #62191. Thanks @neeravmakwana and @maguilar631697. |
23 | 24 | - Security/audit: recognize dangerous node command IDs as valid `gateway.nodes.denyCommands` entries, so audit only warns on real typos or unsupported patterns. (#56923) Thanks @chziyue. |
24 | 25 | - Telegram/exec approvals: stop treating general Telegram chat allowlists and `defaultTo` routes as native exec approvers; Telegram now uses explicit `execApprovals.approvers` or owner identity from `commands.ownerAllowFrom`, matching the first-pairing owner bootstrap path. Thanks @pashpashpash. |
25 | 26 | - Chat commands: route sensitive group `/diagnostics` and `/export-trajectory` approvals and results to a private owner route, preferring same-surface DMs before falling back to the first configured owner route, so Discord group invocations can land in Telegram when that is the primary owner interface. Thanks @pashpashpash. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -22,12 +22,17 @@ export type SentMessageCache = {
|
22 | 22 | // duplicate delivery (noisy but not lossy) — never message loss. |
23 | 23 | const SENT_MESSAGE_TEXT_TTL_MS = 4_000; |
24 | 24 | const SENT_MESSAGE_ID_TTL_MS = 60_000; |
| 25 | +const LEADING_ATTRIBUTED_BODY_CORRUPTION_MARKERS = /^[\uFEFF\uFFFD\uFFFE\uFFFF]+/u; |
25 | 26 | |
26 | 27 | function normalizeEchoTextKey(text: string | undefined): string | null { |
27 | 28 | if (!text) { |
28 | 29 | return null; |
29 | 30 | } |
30 | | -const normalized = text.replace(/\r\n?/g, "\n").trim(); |
| 31 | +const normalized = text |
| 32 | +.replace(/\r\n?/g, "\n") |
| 33 | +.trim() |
| 34 | +.replace(LEADING_ATTRIBUTED_BODY_CORRUPTION_MARKERS, "") |
| 35 | +.trim(); |
31 | 36 | return normalized ? normalized : null; |
32 | 37 | } |
33 | 38 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -17,6 +17,36 @@ describe("iMessage sent-message echo cache", () => {
|
17 | 17 | expect(cache.has("acct:imessage:+1666", { text: "Reasoning:\n_step_" })).toBe(false); |
18 | 18 | }); |
19 | 19 | |
| 20 | +it("matches delayed reflected echoes with leading attributedBody corruption markers", () => { |
| 21 | +vi.useFakeTimers(); |
| 22 | +vi.setSystemTime(new Date("2026-02-25T00:00:00Z")); |
| 23 | +const cache = createSentMessageCache(); |
| 24 | + |
| 25 | +cache.remember("acct:imessage:+1555", { text: "Delayed echo reply" }); |
| 26 | + |
| 27 | +expect( |
| 28 | +cache.has("acct:imessage:+1555", { |
| 29 | +text: "\uFFFD\uFFFE\uFFFF\uFEFFDelayed echo reply", |
| 30 | +}), |
| 31 | +).toBe(true); |
| 32 | +}); |
| 33 | + |
| 34 | +it("keeps attributedBody corruption cleanup leading-only", () => { |
| 35 | +vi.useFakeTimers(); |
| 36 | +vi.setSystemTime(new Date("2026-02-25T00:00:00Z")); |
| 37 | +const cache = createSentMessageCache(); |
| 38 | + |
| 39 | +cache.remember("acct:imessage:+1555", { text: "Delayed echo reply" }); |
| 40 | + |
| 41 | +expect( |
| 42 | +cache.has("acct:imessage:+1555", { |
| 43 | +text: "Delayed \uFFFD echo reply", |
| 44 | +}), |
| 45 | +).toBe(false); |
| 46 | +expect(cache.has("acct:imessage:+1555", { text: "Delayed\techo reply" })).toBe(false); |
| 47 | +expect(cache.has("acct:imessage:+1555", { text: "Delayed\necho reply" })).toBe(false); |
| 48 | +}); |
| 49 | + |
20 | 50 | it("matches by outbound message id and ignores placeholder ids", () => { |
21 | 51 | vi.useFakeTimers(); |
22 | 52 | vi.setSystemTime(new Date("2026-02-25T00:00:00Z")); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。