diff --git a/src/auto-reply/tokens.test.ts b/src/auto-reply/tokens.test.ts new file mode 100644 index 000000000..c8cee251a --- /dev/null +++ b/src/auto-reply/tokens.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from "vitest"; +import { isSilentReplyText } from "./tokens.js"; + +describe("isSilentReplyText", () => { + it("returns true for exact token", () => { + expect(isSilentReplyText("NO_REPLY")).toBe(true); + }); + + it("returns true for token with surrounding whitespace", () => { + expect(isSilentReplyText(" NO_REPLY ")).toBe(true); + expect(isSilentReplyText("\nNO_REPLY\n")).toBe(true); + }); + + it("returns false for undefined/empty", () => { + expect(isSilentReplyText(undefined)).toBe(false); + expect(isSilentReplyText("")).toBe(false); + }); + + it("returns false for substantive text ending with token (#19537)", () => { + const text = "Here is a helpful response.\n\nNO_REPLY"; + expect(isSilentReplyText(text)).toBe(false); + }); + + it("returns false for substantive text starting with token", () => { + const text = "NO_REPLY but here is more content"; + expect(isSilentReplyText(text)).toBe(false); + }); + + it("returns false for token embedded in text", () => { + expect(isSilentReplyText("Please NO_REPLY to this")).toBe(false); + }); + + it("works with custom token", () => { + expect(isSilentReplyText("HEARTBEAT_OK", "HEARTBEAT_OK")).toBe(true); + expect(isSilentReplyText("Checked inbox. HEARTBEAT_OK", "HEARTBEAT_OK")).toBe(false); + }); +}); diff --git a/src/auto-reply/tokens.ts b/src/auto-reply/tokens.ts index c0bce2a2d..18cabceaa 100644 --- a/src/auto-reply/tokens.ts +++ b/src/auto-reply/tokens.ts @@ -11,12 +11,10 @@ export function isSilentReplyText( return false; } const escaped = escapeRegExp(token); - const prefix = new RegExp(`^\\s*${escaped}(?=$|\\W)`); - if (prefix.test(text)) { - return true; - } - const suffix = new RegExp(`\\b${escaped}\\b\\W*$`); - return suffix.test(text); + // Only match when the entire response (trimmed) is the silent token, + // optionally surrounded by whitespace/punctuation. This prevents + // substantive replies ending with NO_REPLY from being suppressed (#19537). + return new RegExp(`^\\s*${escaped}\\s*$`).test(text); } export function isSilentReplyPrefixText(