Skip to content

Commit eeed816

Browse files
zw-xyskclaude
andcommitted
fix(reply): filter short trailing acks after message-tool sends
After an agent delivers its main reply via the message tool, models often append a short meta-ack (已发, OK, Done, Sent, etc.) that becomes a second visible message. Add isMessagingToolAck to detect these by pattern. Fixes #96681 Co-Authored-By: Claude (via Anthropic API) <[email protected]>
1 parent 4ecb45b commit eeed816

3 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/agents/embedded-agent-helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export {
6262
} from "./embedded-agent-helpers/openai.js";
6363
export { sanitizeSessionMessagesImages } from "./embedded-agent-helpers/images.js";
6464
export {
65+
isMessagingToolAck,
6566
isMessagingToolDuplicate,
6667
isMessagingToolDuplicateNormalized,
6768
normalizeTextForComparison,

src/agents/embedded-agent-helpers/messaging-dedupe.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/st
66
const MIN_DUPLICATE_TEXT_LENGTH = 10;
77
const MIN_REVERSE_SUBSTRING_DUPLICATE_RATIO = 0.5;
88

9+
/** Common ack patterns that carry no information beyond a preceding message-tool send. */
10+
const ACK_PATTERNS = [
11+
// English — trailing after message-tool send
12+
/\b(sent|done|ok|okay|roger|got it|thanks|thank you)\b\s*\.?\s*#?\d*$/iu,
13+
// Chinese
14+
/(|||||||||)/u,
15+
];
16+
17+
/** Maximum length for a message to be considered a meta-ack. */
18+
const MAX_ACK_LENGTH = 200;
19+
920
/**
1021
* Normalize text for duplicate comparison.
1122
* - Trims whitespace
@@ -45,6 +56,18 @@ export function isMessagingToolDuplicateNormalized(
4556
});
4657
}
4758

59+
/** Return true when the text is a short meta-ack after a message-tool send. */
60+
export function isMessagingToolAck(text: string, sentTexts: string[]): boolean {
61+
if (sentTexts.length === 0) {
62+
return false;
63+
}
64+
const trimmed = (text ?? "").trim();
65+
if (!trimmed || trimmed.length > MAX_ACK_LENGTH) {
66+
return false;
67+
}
68+
return ACK_PATTERNS.some((pattern) => pattern.test(trimmed));
69+
}
70+
4871
/** Return true when raw message text duplicates a prior sent message. */
4972
export function isMessagingToolDuplicate(text: string, sentTexts: string[]): boolean {
5073
if (sentTexts.length === 0) {

src/auto-reply/reply/reply-payloads-dedupe.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
normalizeLowercaseStringOrEmpty,
44
normalizeOptionalString,
55
} from "@openclaw/normalization-core/string-coerce";
6-
import { isMessagingToolDuplicate } from "../../agents/embedded-agent-helpers.js";
6+
import {
7+
isMessagingToolAck,
8+
isMessagingToolDuplicate,
9+
} from "../../agents/embedded-agent-helpers.js";
710
import type { MessagingToolSend } from "../../agents/embedded-agent-messaging.types.js";
811
import { getChannelPlugin } from "../../channels/plugins/index.js";
912
import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-loaded-read.js";
@@ -31,7 +34,8 @@ export function filterMessagingToolDuplicates(params: {
3134
if (payload.mediaUrl || payload.mediaUrls?.length) {
3235
return true;
3336
}
34-
return !isMessagingToolDuplicate(payload.text ?? "", sentTexts);
37+
const text = payload.text ?? "";
38+
return !isMessagingToolDuplicate(text, sentTexts) && !isMessagingToolAck(text, sentTexts);
3539
});
3640
}
3741

0 commit comments

Comments
 (0)