feat: kill conversations on off-platform and seller pushes
Seller detection on replies was a case-insensitive substring match over the configured keyword list, and every hit landed in `human-required` alongside genuine prospects that need a person. Off-platform pushes were only checked for r4r policy modes, as were the under-18 signals. Three layers now: - New `off-platform-signals` module matches on normalized text (unicode folding, zero-width stripping, leet mapping, separator removal), so `0nlyf4ns`, `t3l3gr4m` and `t e l e g r a m` are caught. Ambiguous terms need context: `snap` on its own stays a photo request, never a kill. - New terminal `killed` automation status. It records the evidence, sets the durable seller flag, supersedes the pending claim, and resolves triage to `done`, so killed conversations leave every actionable queue. Off-platform kills are independent of `reddit.filterSellers`. - Optional AI screening of inbound replies behind `conversations.aiReplyScreening` (off by default). Runs only after the deterministic gates pass, memoizes per inbound event, and fails open. Under-18 and in-person/contact-detail signals now apply to every policy mode rather than r4r only, and remain human handoffs rather than kills. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ac12a3146a
commit
4404ae75ff
18 files changed
+907
-31
No files matched your search
@@ -123,6 +123,30 @@ export const ConfigSchema = z.object({
|
||||
'justfor.fans',
|
||||
]),
|
||||
}),
|
||||
conversations: z.object({
|
||||
/**
|
||||
* Ends a conversation outright when the other party pushes it to another
|
||||
* app, to contact details, or to a payment rail. This is a safety control
|
||||
* rather than a lead-quality filter, so it is independent of
|
||||
* `reddit.filterSellers`.
|
||||
*/
|
||||
offPlatformKill: z.boolean().default(true),
|
||||
/** Whether a configured seller keyword or domain also ends the conversation. */
|
||||
killOnSellerKeyword: z.boolean().default(true),
|
||||
/**
|
||||
* Second-stage AI screening of inbound replies. Runs only when the
|
||||
* deterministic rules come up clean, and fails open.
|
||||
*/
|
||||
aiReplyScreening: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
killConfidence: z.number().min(0).max(1).default(0.8),
|
||||
flagConfidence: z.number().min(0).max(1).default(0.6),
|
||||
}).default({ enabled: false, killConfidence: 0.8, flagConfidence: 0.6 }),
|
||||
}).default({
|
||||
offPlatformKill: true,
|
||||
killOnSellerKeyword: true,
|
||||
aiReplyScreening: { enabled: false, killConfidence: 0.8, flagConfidence: 0.6 },
|
||||
}),
|
||||
openrouter: z.object({
|
||||
apiKey: z.string(),
|
||||
imageAnalysisModel: z.string().default('google/gemini-3-flash-preview'),
|
||||
|
||||
Reference in new issue
Block a user