From 4211140889dda1ddfa7639f683845e7ad46c1d71 Mon Sep 17 00:00:00 2001 From: ARIA Date: Wed, 13 May 2026 10:07:06 +0000 Subject: [PATCH] ARIA self-improvement: filter promo senders from active-threads surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The active-threads block in think/reflect prompts was concatenating 11+ unrelated promo/notification senders (AutoScout24, AliExpress, Glassdoor, MijnOverheid, Ferrari newsletter, LinkedIn job alerts, etc.) under one subject line. They share the gmail: thread key so they all aggregate into a single "thread" that drowns out real conversations and wastes prompt budget. Add isPromoSender() in brain-prompt.ts using common no-reply / newsletter / jobalerts / savedsearches local-part patterns plus a small denylist of marketing domains. Filter participants when rendering the Active threads section; suppress a thread entirely if every participant matches. Raw observations are untouched — only the prompt-side aggregation is filtered. Intent-summary: Active-threads prompt surface was bundling many promotional/notification email senders into one fake thread, polluting reasoning context with inbox noise. Intent-tokens: active-threads, promo-filter, email-noise, prompt-noise, gmail, newsletter, noreply --- backend/brain-prompt.ts | 48 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/backend/brain-prompt.ts b/backend/brain-prompt.ts index f62fd95f..53be8e90 100644 --- a/backend/brain-prompt.ts +++ b/backend/brain-prompt.ts @@ -56,6 +56,40 @@ function timeAgo(ts: number): string { return `${days}d ago`; } +// Promo / routine notification sender patterns. Used to drop noise participants +// from the active-threads surface — many of these accumulate under a single +// gmail: thread key and crowd out real conversations. Raw observations +// remain logged; only the prompt-side aggregation is filtered. +const PROMO_LOCAL_PATTERNS: RegExp[] = [ + /no-?reply@/i, + /do-?not-?reply@/i, + /newsletter@/i, + /notifications?@/i, + /savedsearches?@/i, + /jobalerts(?:-noreply)?@/i, + /best-message-notice@/i, +]; + +const PROMO_DOMAIN_KEYWORDS: string[] = [ + "aliexpress", + "autoscout24", + "glassdoor", + "ferrari", + "mijn.overheid", + "marktplaats", + "quora", +]; + +function isPromoSender(sender: string): boolean { + if (!sender) return false; + const match = /<([^>]+)>/.exec(sender); + const addr = (match ? match[1] : sender).trim().toLowerCase(); + if (PROMO_LOCAL_PATTERNS.some(re => re.test(addr))) return true; + const domain = addr.includes("@") ? addr.split("@")[1] || "" : addr; + if (PROMO_DOMAIN_KEYWORDS.some(kw => domain.includes(kw))) return true; + return false; +} + function formatSingleObservation(obs: Observation): string { const time = formatTime(obs.timestamp); const who = obs.isFromMe ? `${obs.sender || "Me"} (you/outgoing)` : obs.sender || "Unknown"; @@ -318,7 +352,19 @@ function formatWorkingMemory(wm: WorkingMemory): string { // Active conversation threads if (wm.conversationThreads && wm.conversationThreads.length > 0) { - const activeThreads = wm.conversationThreads.filter(t => t.status === "active").slice(0, 5); + const activeThreads = wm.conversationThreads + .filter(t => t.status === "active") + // Drop promo/notification senders from participants. If a thread is + // entirely promo (e.g. the gmail: bucket where unrelated + // newsletters pile up), suppress it entirely. + .map(t => { + const filtered = Array.isArray(t.participants) + ? t.participants.filter(p => !isPromoSender(p)) + : t.participants; + return { ...t, participants: filtered }; + }) + .filter(t => Array.isArray(t.participants) ? t.participants.length > 0 : !!t.participants) + .slice(0, 5); if (activeThreads.length > 0) { const threadLines = activeThreads.map(t => { const who = Array.isArray(t.participants) ? t.participants.join(", ") : (t.participants || "unknown");