Show the language model's opinion on a message
When inbuxa-server's AI spam classification is on, it records the model's answer in an X-Spam-LLM header: a tag (LLM_<category>[_<confidence>]) and, in parentheses, the model's explanation. The full message now asks for it, and where it's there: - the message details show "Language model's opinion" beside the spam filter's own working, with category, confidence and explanation; - a message in Junk carries a banner saying the same. Both say it's one of several signals the spam filter weighed, never the reason on its own, as the server's spec requires. The explanation is model output and is only ever rendered as text. Nothing shows without the header, so a server without the feature, or with it off, looks as before. Translations: two new strings, "Language model's opinion" and "One of several signals the spam filter weighed", in all eight catalogues (16 entries). Category and confidence come from the server and aren't translated.
This commit is contained in:
1 parent
c0c892dd33
commit
e4926cfa7d
17 files changed
+319
No files matched your search
@@ -0,0 +1,52 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { LLM_HEADER_PROP, llmOpinion, parseLlmOpinion } from "@/lib/llmOpinion";
|
||||
|
||||
/*
|
||||
* The header as inbuxa-server writes it (crates/features/src/ai/answer.rs):
|
||||
* `X-Spam-LLM: <TAG>`, optionally followed by the explanation in one pair of
|
||||
* parentheses, folded at 78 columns.
|
||||
*/
|
||||
describe("parseLlmOpinion", () => {
|
||||
it("reads category, confidence and explanation", () => {
|
||||
expect(parseLlmOpinion("LLM_UNSOLICITED_HIGH (Promotes a product the reader never asked about)")).toEqual({
|
||||
tag: "LLM_UNSOLICITED_HIGH",
|
||||
category: "Unsolicited",
|
||||
confidence: "High",
|
||||
explanation: "Promotes a product the reader never asked about",
|
||||
});
|
||||
});
|
||||
|
||||
it("reads a tag with no confidence and no explanation", () => {
|
||||
expect(parseLlmOpinion("LLM_LEGITIMATE")).toEqual({
|
||||
tag: "LLM_LEGITIMATE",
|
||||
category: "Legitimate",
|
||||
confidence: null,
|
||||
explanation: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps an operator's multi-word category whole", () => {
|
||||
const o = parseLlmOpinion("LLM_COLD_OUTREACH_MEDIUM");
|
||||
expect(o?.category).toBe("Cold outreach");
|
||||
expect(o?.confidence).toBe("Medium");
|
||||
// An unknown last word is part of the category, not a confidence.
|
||||
expect(parseLlmOpinion("LLM_COLD_OUTREACH")?.category).toBe("Cold outreach");
|
||||
expect(parseLlmOpinion("LLM_COLD_OUTREACH")?.confidence).toBeNull();
|
||||
});
|
||||
|
||||
it("unfolds a folded header and keeps inner parentheses", () => {
|
||||
const o = parseLlmOpinion("LLM_HARMFUL_LOW (Asks for a password\r\n (urgently) via a link)");
|
||||
expect(o?.explanation).toBe("Asks for a password (urgently) via a link");
|
||||
});
|
||||
|
||||
it("returns null for anything that isn't the server's tag", () => {
|
||||
for (const raw of [null, undefined, "", " ", "Yes, score=6.7", "LLM_", "llm_unsolicited_high", "X LLM_SPAM"]) {
|
||||
expect(parseLlmOpinion(raw), String(raw)).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it("reads the JMAP property a full message carries", () => {
|
||||
expect(llmOpinion({ [LLM_HEADER_PROP]: "LLM_LEGITIMATE_HIGH" })?.category).toBe("Legitimate");
|
||||
expect(llmOpinion({})).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user