Skip to content

Commit eec4bb7

Browse files
committed
fix(imessage): normalize leading echo-cache corruption bytes
1 parent ba15382 commit eec4bb7

3 files changed

Lines changed: 26 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
1212

1313
### Fixes
1414

15+
- iMessage/echo cache: strip only leading imsg corruption bytes from reflected text keys while preserving interior control characters, so duplicate-reply suppression does not collapse unrelated messages. (#62191) Thanks @maguilar631697.
1516
- NVIDIA/NIM: persist the `NVIDIA_API_KEY` provider marker and mark bundled NVIDIA Chat Completions models as string-content compatible, so NIM models load from `models.json` and OpenAI-compatible subagent calls send plain text content. Fixes #73013 and #50107; refs #73014. Thanks @bautrey, @iot2edge, @ifearghal, and @futhgar.
1617
- Channels/Discord: let text-only configs drop the `GuildVoiceStates` gateway intent and expose a bounded `/gateway/bot` metadata timeout with rate-limited fallback logs, reducing idle CPU and warning floods. Fixes #73709 and #73585. Thanks @sanchezm86 and @trac3r00.
1718
- CLI/plugins: use plugin metadata snapshots for install slot selection and add opt-in plugin lifecycle timing traces, so plugin install avoids runtime-loading the plugin registry for metadata-only decisions. Thanks @shakkernerd.

extensions/imessage/src/monitor/echo-cache.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,16 @@ export type SentMessageCache = {
2323
const SENT_MESSAGE_TEXT_TTL_MS = 4_000;
2424
const SENT_MESSAGE_ID_TTL_MS = 60_000;
2525

26-
// U+FFFD replacement characters and C0/C1 control characters that imsg injects when
27-
// extracting text from NSAttributedString (attributedBody column). The pattern intentionally
28-
// matches control characters to strip garbage from echo cache keys. See: #61312, #61821
26+
// U+FFFD replacement characters and C0/C1 control characters that imsg can prepend when
27+
// extracting text from NSAttributedString (attributedBody column). Keep interior text intact.
2928
// eslint-disable-next-line no-control-regex
30-
const IMSG_GARBAGE_CHARS_RE =
31-
/[\ufffd\ufffe\uffff\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]+/g;
29+
const LEADING_IMSG_GARBAGE_CHARS_RE = /^[\ufffd\ufffe\uffff\u0000-\u001f\u007f-\u009f]+/;
3230

3331
function normalizeEchoTextKey(text: string | undefined): string | null {
3432
if (!text) {
3533
return null;
3634
}
37-
const normalized = text.replace(IMSG_GARBAGE_CHARS_RE, "").replace(/\r\n?/g, "\n").trim();
35+
const normalized = text.replace(LEADING_IMSG_GARBAGE_CHARS_RE, "").replace(/\r\n?/g, "\n").trim();
3836
return normalized ? normalized : null;
3937
}
4038

extensions/imessage/src/monitor/monitor-provider.echo-cache.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,27 @@ describe("iMessage sent-message echo cache", () => {
1717
expect(cache.has("acct:imessage:+1666", { text: "Reasoning:\n_step_" })).toBe(false);
1818
});
1919

20+
it("strips leading imsg corruption bytes from text keys", () => {
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: "\ufffd\u0000Reasoning:\n\t_step_" });
26+
27+
expect(cache.has("acct:imessage:+1555", { text: "Reasoning:\n\t_step_" })).toBe(true);
28+
});
29+
30+
it("preserves interior control characters in text keys", () => {
31+
vi.useFakeTimers();
32+
vi.setSystemTime(new Date("2026-02-25T00:00:00Z"));
33+
const cache = createSentMessageCache();
34+
35+
cache.remember("acct:imessage:+1555", { text: "alpha\u0007beta\n\tgamma" });
36+
37+
expect(cache.has("acct:imessage:+1555", { text: "alpha\u0007beta\n\tgamma" })).toBe(true);
38+
expect(cache.has("acct:imessage:+1555", { text: "alphabeta\n\tgamma" })).toBe(false);
39+
});
40+
2041
it("matches by outbound message id and ignores placeholder ids", () => {
2142
vi.useFakeTimers();
2243
vi.setSystemTime(new Date("2026-02-25T00:00:00Z"));

0 commit comments

Comments
 (0)