AI spam classification: the model's opinion as one bounded spam signal, and the llm_prompt Sieve function (AI-1 to AI-28)
The classifier sends only the subject and text, between unforgeable markers after the operator's prompt, to an OpenAI-compatible endpoint the operator configured; nothing is preset. Its answer maps to an LLM_ tag whose score is clamped (+5.0, -1.0 by default) and can never discard or reject on its own; X-Spam-LLM is sanitized, encoded and folded, and a planted one is removed. Failures, timeouts past the ceiling, a full slot or a paused model leave mail flowing untagged. llm_prompt answers trusted scripts, and accounts holding interactAi within an hourly limit. Redirects aren't followed and no content or secret is logged. The limits live in inbuxa:AiLimits. Acceptance tests 1 and 3 to 21; test 2 as the re-enabled shared llm case, whose setup no longer waits on a rules file from a developer's own path; test 22 written as the ignored ai_compat.
This commit is contained in:
@@ -426,15 +426,26 @@ impl SpamFilterLists {
|
||||
&tag.tag,
|
||||
SpamFilterAction::Allow(tag.score.into_inner() as f32),
|
||||
),
|
||||
SpamTag::Discard(tag) => lists
|
||||
.scores
|
||||
.insert_pattern(&tag.tag, SpamFilterAction::Discard),
|
||||
SpamTag::Reject(tag) => lists
|
||||
.scores
|
||||
.insert_pattern(&tag.tag, SpamFilterAction::Reject),
|
||||
SpamTag::Discard(tag) => {
|
||||
warn_llm_refusal(&tag.tag);
|
||||
lists
|
||||
.scores
|
||||
.insert_pattern(&tag.tag, SpamFilterAction::Discard)
|
||||
}
|
||||
SpamTag::Reject(tag) => {
|
||||
warn_llm_refusal(&tag.tag);
|
||||
lists
|
||||
.scores
|
||||
.insert_pattern(&tag.tag, SpamFilterAction::Reject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inbuxa: AI-2: at start and each reload, models off this network are flagged
|
||||
for model in bp.list_infallible::<registry::schema::structs::AiModel>().await {
|
||||
crate::enterprise::llm::warn_if_remote(&model.object).await;
|
||||
}
|
||||
|
||||
for ext in bp.list_infallible::<SpamFileExtension>().await {
|
||||
let ext = ext.object;
|
||||
lists.file_extensions.insert_pattern(
|
||||
@@ -740,3 +751,16 @@ mod tests {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// inbuxa: AI-13: a Discard or Reject on the model's tag counts as no entry
|
||||
fn warn_llm_refusal(tag: &str) {
|
||||
if inbuxa_features::ai::answer::is_llm_tag(tag) {
|
||||
trc::event!(
|
||||
Registry(trc::RegistryEvent::BuildWarning),
|
||||
Details = format!(
|
||||
"Spam tag {tag} discards or rejects, which the language model's opinion alone \
|
||||
may not do: it scores 0 (AI-13)"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user