radmail-mcp 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/dist/api/mcp.d.ts +3 -0
- package/dist/api/mcp.js +44 -0
- package/dist/api/mcp.js.map +1 -0
- package/dist/src/engine/importance-score.d.ts +122 -0
- package/dist/src/engine/importance-score.js +352 -0
- package/dist/src/engine/importance-score.js.map +1 -0
- package/dist/src/engine/send-disposition.d.ts +37 -0
- package/dist/src/engine/send-disposition.js +112 -0
- package/dist/src/engine/send-disposition.js.map +1 -0
- package/dist/src/engine/signals.d.ts +116 -0
- package/dist/src/engine/signals.js +287 -0
- package/dist/src/engine/signals.js.map +1 -0
- package/dist/src/engine/types.d.ts +20 -0
- package/dist/src/engine/types.js +52 -0
- package/dist/src/engine/types.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/commitment.d.ts +24 -0
- package/dist/src/lib/commitment.js +123 -0
- package/dist/src/lib/commitment.js.map +1 -0
- package/dist/src/lib/connected.d.ts +112 -0
- package/dist/src/lib/connected.js +150 -0
- package/dist/src/lib/connected.js.map +1 -0
- package/dist/src/lib/demand-sink.d.ts +23 -0
- package/dist/src/lib/demand-sink.js +87 -0
- package/dist/src/lib/demand-sink.js.map +1 -0
- package/dist/src/lib/learning.d.ts +35 -0
- package/dist/src/lib/learning.js +103 -0
- package/dist/src/lib/learning.js.map +1 -0
- package/dist/src/lib/taint.d.ts +35 -0
- package/dist/src/lib/taint.js +65 -0
- package/dist/src/lib/taint.js.map +1 -0
- package/dist/src/lib/tenants.d.ts +21 -0
- package/dist/src/lib/tenants.js +55 -0
- package/dist/src/lib/tenants.js.map +1 -0
- package/dist/src/lib/triage.d.ts +83 -0
- package/dist/src/lib/triage.js +278 -0
- package/dist/src/lib/triage.js.map +1 -0
- package/dist/src/server.d.ts +9 -0
- package/dist/src/server.js +40 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/tools.d.ts +302 -0
- package/dist/src/tools.js +737 -0
- package/dist/src/tools.js.map +1 -0
- package/dist/test/connected.test.d.ts +1 -0
- package/dist/test/connected.test.js +514 -0
- package/dist/test/connected.test.js.map +1 -0
- package/dist/test/demand-sink.test.d.ts +1 -0
- package/dist/test/demand-sink.test.js +137 -0
- package/dist/test/demand-sink.test.js.map +1 -0
- package/dist/test/firewall.test.d.ts +1 -0
- package/dist/test/firewall.test.js +210 -0
- package/dist/test/firewall.test.js.map +1 -0
- package/dist/test/taint.test.d.ts +1 -0
- package/dist/test/taint.test.js +90 -0
- package/dist/test/taint.test.js.map +1 -0
- package/package.json +53 -0
- package/src/engine/importance-score.ts +462 -0
- package/src/engine/send-disposition.ts +173 -0
- package/src/engine/signals.ts +403 -0
- package/src/engine/types.ts +73 -0
- package/src/index.ts +21 -0
- package/src/lib/commitment.ts +143 -0
- package/src/lib/connected.ts +291 -0
- package/src/lib/demand-sink.ts +102 -0
- package/src/lib/learning.ts +136 -0
- package/src/lib/taint.ts +87 -0
- package/src/lib/tenants.ts +67 -0
- package/src/lib/triage.ts +358 -0
- package/src/server.ts +50 -0
- package/src/tools.ts +932 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importance-score.js","sourceRoot":"","sources":["../../../src/engine/importance-score.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CommitmentDirection, CommitmentActionType } from "./types.js";
|
|
2
|
+
export type SendDispositionContext = {
|
|
3
|
+
direction: CommitmentDirection;
|
|
4
|
+
actionType: CommitmentActionType;
|
|
5
|
+
tenantOptedInClass: boolean;
|
|
6
|
+
entitled: boolean;
|
|
7
|
+
counterpartyKnown: boolean;
|
|
8
|
+
recipientDomainAllowed: boolean;
|
|
9
|
+
scrubberClean: boolean;
|
|
10
|
+
completionRecheckedOpen: boolean;
|
|
11
|
+
alreadySent: boolean;
|
|
12
|
+
hasMoneySignal: boolean;
|
|
13
|
+
hasNewBankingSignal: boolean;
|
|
14
|
+
hasDecisionSignal: boolean;
|
|
15
|
+
injectionSignal: boolean;
|
|
16
|
+
/** sla_basis: a guessed deadline ('default_by_type') never auto-sends. */
|
|
17
|
+
slaBasis?: "explicit" | "relative" | "default_by_type" | "manual";
|
|
18
|
+
};
|
|
19
|
+
export type SendDisposition = {
|
|
20
|
+
disposition: "auto_send";
|
|
21
|
+
} | {
|
|
22
|
+
disposition: "needs_approval";
|
|
23
|
+
reason: string;
|
|
24
|
+
} | {
|
|
25
|
+
disposition: "hard_stop";
|
|
26
|
+
reason: string;
|
|
27
|
+
};
|
|
28
|
+
export type SourceRiskSignals = {
|
|
29
|
+
hasMoneySignal: boolean;
|
|
30
|
+
hasNewBankingSignal: boolean;
|
|
31
|
+
hasDecisionSignal: boolean;
|
|
32
|
+
injectionSignal: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** Scan the SOURCE-side text (subject + commitment action + verbatim evidence span)
|
|
35
|
+
* for BEC risk. Pass every available source string; nulls are ignored. */
|
|
36
|
+
export declare function detectSourceRiskSignals(...parts: Array<string | null | undefined>): SourceRiskSignals;
|
|
37
|
+
export declare function commitmentSendDisposition(ctx: SendDispositionContext): SendDisposition;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// PORTED VERBATIM (pure, no-DB) from the RadMail main app:
|
|
3
|
+
// /Users/GreenLife/Documents/CODE/RadMail/src/server/commitments/send-disposition.ts
|
|
4
|
+
// Recovered into radmail-mcp so the MCP sandbox runs the SAME deterministic BEC
|
|
5
|
+
// firewall as production. This is the sacred firewall — it may only be TIGHTENED,
|
|
6
|
+
// never loosened. Keep byte-for-byte with source.
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// The action types that may EVER auto-send (the narrowest class).
|
|
9
|
+
function isAutoSendableType(t) {
|
|
10
|
+
return t === "follow_up";
|
|
11
|
+
}
|
|
12
|
+
// The action types that are PERMANENTLY human-only (hard-stop forever).
|
|
13
|
+
function isHardStopType(t) {
|
|
14
|
+
return t === "payment" || t === "decision" || t === "contact_third_party" || t === "send_deliverable";
|
|
15
|
+
}
|
|
16
|
+
// ── Deterministic source-side BEC risk detection (pure, pin-tested). ──
|
|
17
|
+
// Doctrine: a false positive (one extra human review) is cheap; a false negative
|
|
18
|
+
// (auto-sending money / banking-change / decision mail) is catastrophic. These
|
|
19
|
+
// patterns fire READILY by design — when in doubt, hard-stop to a human.
|
|
20
|
+
const MONEY_RE = /(\$\s?\d)|(\b\d{2,}\s?(usd|dollars|eur|gbp)\b)|\b(wire\s?transfer|wire|remit\w*|invoice|payment|deposit|ach|routing\s?number|swift|iban|amount\s?due|balance\s?due|past\s?due|payable|payout)\b/i;
|
|
21
|
+
const BANKING_RE = /\b(new|updated?|chang(?:e|ed|ing)|revis\w+|different|switch(?:ed)?)\b[^.!?\n]{0,50}\b(bank\w*|account|remit\w*|wire|routing|payment\s+(?:details|info|information|instructions))\b/i;
|
|
22
|
+
const BANKING_RE2 = /\b(bank\w*|account|routing|remit\w*|wire|payment\s+(?:details|info|information|instructions))\b[^.!?\n]{0,50}\b(chang(?:e|ed|ing)|updated?|new|revis\w+|different)\b/i;
|
|
23
|
+
const DECISION_RE = /\b(approv\w+|sign[\s-]?off|signoff|authoriz\w+|go[\s-]?ahead|green[\s-]?light)\b|\b(please\s+)?confirm\b[^.!?\n]{0,30}\b(order|po|purchase|wire|payment|deal|contract|invoice)\b/i;
|
|
24
|
+
// Prompt-injection in inbound mail that could steer an autonomous reply. Expanded
|
|
25
|
+
// for the autonomy path — a single "ignore previous instructions" regex is too thin
|
|
26
|
+
// once mail can drive an action. Fires readily (false-positive bias = an extra human
|
|
27
|
+
// review). NOT a complete defense; the human hard-stop is the floor.
|
|
28
|
+
const INJECTION_RE = /\b(ignore\s+(?:all\s+|the\s+|any\s+)?(?:previous|prior|above|earlier)\s+(?:instructions?|prompts?|messages?|context)|disregard\s+(?:your|the|all|any)\s+(?:instructions?|rules?|guidelines?)|system\s+prompt|developer\s+(?:message|prompt)|you\s+are\s+now\s+|new\s+instructions?\s*:|prior\s+instructions?\s+(?:no\s+longer|do\s+not)\s+apply|do\s+not\s+(?:tell|inform|mention\s+to)\s+(?:the\s+)?(?:user|human|operator)|instead\s+of\s+(?:replying|responding|your\s+task)|when\s+you\s+reply[, ].{0,40}\b(?:cc|bcc|forward|send\s+to)\b|<\s*(?:system|assistant)\s*>)\b/i;
|
|
29
|
+
/** Normalize text to defeat trivial injection obfuscation before scanning:
|
|
30
|
+
* strip zero-width / bidi unicode, and decode long base64 runs (appended so the
|
|
31
|
+
* decoded payload is also scanned). Pure + cheap. */
|
|
32
|
+
function normalizeForScan(text) {
|
|
33
|
+
// Cap the scanned span — the real call sites pass short strings (subject + the
|
|
34
|
+
// ≤140-char action + the evidence sentence); the cap defends the public fn from
|
|
35
|
+
// a huge body causing regex backtracking / a giant match array.
|
|
36
|
+
const t = text.slice(0, 16_384).replace(/[--]/g, "");
|
|
37
|
+
const decoded = [];
|
|
38
|
+
// Bound each base64 run (24..512) and the number of decodes (≤16) for safety.
|
|
39
|
+
for (const m of (t.match(/[A-Za-z0-9+/]{24,512}={0,2}/g) ?? []).slice(0, 16)) {
|
|
40
|
+
try {
|
|
41
|
+
const d = Buffer.from(m, "base64").toString("utf8");
|
|
42
|
+
// Only keep decodes that look like readable text (avoid binary noise).
|
|
43
|
+
if (d && /[\x20-\x7e]{8,}/.test(d) && !/[\x00-\x08\x0e-\x1f]/.test(d))
|
|
44
|
+
decoded.push(d);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
/* not valid base64 — ignore */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return decoded.length ? `${t}\n${decoded.join("\n")}` : t;
|
|
51
|
+
}
|
|
52
|
+
/** Scan the SOURCE-side text (subject + commitment action + verbatim evidence span)
|
|
53
|
+
* for BEC risk. Pass every available source string; nulls are ignored. */
|
|
54
|
+
export function detectSourceRiskSignals(...parts) {
|
|
55
|
+
const raw = parts.filter((p) => !!p).join("\n");
|
|
56
|
+
// Injection scan runs over the de-obfuscated text (zero-width stripped, base64
|
|
57
|
+
// decoded); money/banking/decision scan over raw (those don't get obfuscated).
|
|
58
|
+
const scan = normalizeForScan(raw);
|
|
59
|
+
return {
|
|
60
|
+
hasMoneySignal: MONEY_RE.test(raw),
|
|
61
|
+
hasNewBankingSignal: BANKING_RE.test(raw) || BANKING_RE2.test(raw),
|
|
62
|
+
hasDecisionSignal: DECISION_RE.test(raw),
|
|
63
|
+
injectionSignal: INJECTION_RE.test(raw) || INJECTION_RE.test(scan),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function commitmentSendDisposition(ctx) {
|
|
67
|
+
// ── FAIL-CLOSED: the four BEC risk signals MUST be evaluated by the caller.
|
|
68
|
+
// If any arrives non-boolean (detection was never wired), refuse to auto-send.
|
|
69
|
+
// This is the runtime backstop to the compile-time `required` contract above. ──
|
|
70
|
+
for (const k of ["hasMoneySignal", "hasNewBankingSignal", "hasDecisionSignal", "injectionSignal"]) {
|
|
71
|
+
if (typeof ctx[k] !== "boolean") {
|
|
72
|
+
return { disposition: "hard_stop", reason: `risk signal ${k} not evaluated — fail-closed (BEC defense)` };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ── PERMANENT HARD-STOPS first — these can never be overridden. ──
|
|
76
|
+
if (isHardStopType(ctx.actionType)) {
|
|
77
|
+
return { disposition: "hard_stop", reason: `action_type=${ctx.actionType} is human-only forever` };
|
|
78
|
+
}
|
|
79
|
+
if (ctx.hasMoneySignal)
|
|
80
|
+
return { disposition: "hard_stop", reason: "money signal — human-only (BEC defense)" };
|
|
81
|
+
if (ctx.hasNewBankingSignal)
|
|
82
|
+
return { disposition: "hard_stop", reason: "new-banking signal — human-only (BEC defense)" };
|
|
83
|
+
if (ctx.hasDecisionSignal)
|
|
84
|
+
return { disposition: "hard_stop", reason: "decision signal — human-only" };
|
|
85
|
+
if (ctx.injectionSignal)
|
|
86
|
+
return { disposition: "hard_stop", reason: "injection/anomaly signal — escalate" };
|
|
87
|
+
// ── AUTO-SEND requires the FULL AND-gate. Any miss → needs_approval. ──
|
|
88
|
+
if (ctx.direction !== "owed_by_us") {
|
|
89
|
+
return { disposition: "needs_approval", reason: "owed_to_us — nudge starts human-gated" };
|
|
90
|
+
}
|
|
91
|
+
if (!isAutoSendableType(ctx.actionType)) {
|
|
92
|
+
return { disposition: "needs_approval", reason: `action_type=${ctx.actionType} is not an auto-sendable class` };
|
|
93
|
+
}
|
|
94
|
+
if (!ctx.tenantOptedInClass)
|
|
95
|
+
return { disposition: "needs_approval", reason: "tenant has not opted into auto-send for this class" };
|
|
96
|
+
if (!ctx.entitled)
|
|
97
|
+
return { disposition: "needs_approval", reason: "autonomous_followup not entitled (Pro+)" };
|
|
98
|
+
if (!ctx.counterpartyKnown)
|
|
99
|
+
return { disposition: "needs_approval", reason: "counterparty not known" };
|
|
100
|
+
if (!ctx.recipientDomainAllowed)
|
|
101
|
+
return { disposition: "needs_approval", reason: "recipient domain not allowlisted" };
|
|
102
|
+
if (!ctx.scrubberClean)
|
|
103
|
+
return { disposition: "needs_approval", reason: "outbound scrubber not clean" };
|
|
104
|
+
if (!ctx.completionRecheckedOpen)
|
|
105
|
+
return { disposition: "needs_approval", reason: "completion re-check did not confirm open" };
|
|
106
|
+
if (ctx.alreadySent)
|
|
107
|
+
return { disposition: "needs_approval", reason: "a follow-up was already sent (single-send dedup)" };
|
|
108
|
+
if (ctx.slaBasis === "default_by_type")
|
|
109
|
+
return { disposition: "needs_approval", reason: "due date was guessed (default_by_type) — never auto-send on a guessed deadline" };
|
|
110
|
+
return { disposition: "auto_send" };
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=send-disposition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-disposition.js","sourceRoot":"","sources":["../../../src/engine/send-disposition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export declare const CATEGORY_PRIORS: Record<string, number>;
|
|
2
|
+
export declare const DEFAULT_CATEGORY_PRIOR = 40;
|
|
3
|
+
export declare function categoryPrior(classification: string | null): number;
|
|
4
|
+
export interface SenderStats {
|
|
5
|
+
/** Distinct inbound emails seen from this sender (the denominator). */
|
|
6
|
+
emailCount: number;
|
|
7
|
+
/** How many the user replied to. */
|
|
8
|
+
replyCount: number;
|
|
9
|
+
/** How many the user opened (firstViewed). */
|
|
10
|
+
openCount: number;
|
|
11
|
+
/** How many were archived without ever being opened (negative signal). */
|
|
12
|
+
archivedUnreadCount: number;
|
|
13
|
+
/** Times the user pulled this sender's mail OUT of the digest (strong +). */
|
|
14
|
+
pullbackCount: number;
|
|
15
|
+
/** The online-EW learned action-likelihood score in [0,100]. */
|
|
16
|
+
learnedScore: number;
|
|
17
|
+
/** ISO/Date of the most recent inbound we corresponded around, or null. */
|
|
18
|
+
lastCorrespondedAt: string | Date | null;
|
|
19
|
+
}
|
|
20
|
+
/** A fresh, never-seen sender (cold start). */
|
|
21
|
+
export declare function emptySenderStats(): SenderStats;
|
|
22
|
+
export interface ThreadSignal {
|
|
23
|
+
/** The user has replied IN this thread before (participation). */
|
|
24
|
+
userInThread: boolean;
|
|
25
|
+
/** This inbound is a reply to a user's outbound — closes a waiting-on. */
|
|
26
|
+
isReplyToUserOutbound: boolean;
|
|
27
|
+
/** How deep the thread is (more back-and-forth = more invested). */
|
|
28
|
+
threadDepth: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function emptyThreadSignal(): ThreadSignal;
|
|
31
|
+
/** Action-count at which the learned per-sender score is fully trusted. */
|
|
32
|
+
export declare const LEARN_KNEE = 5;
|
|
33
|
+
/** Recency: behavior within this many days is "fresh" (full strength). */
|
|
34
|
+
export declare const RECENCY_FULL_DAYS = 14;
|
|
35
|
+
/** Recency fully decays to half-strength by this horizon. */
|
|
36
|
+
export declare const RECENCY_HALF_DAYS = 60;
|
|
37
|
+
/** Hard cap on total points behavior can ADD to the content score. The cap is
|
|
38
|
+
* generous enough that a reliably-replied, recent correspondent (the buried-
|
|
39
|
+
* recall case) clears the 'high' band off a near-zero content base, but small
|
|
40
|
+
* enough that behavior can never manufacture a 'critical' (≥80) on its own. */
|
|
41
|
+
export declare const BEHAVIOR_MAX_POINTS = 42;
|
|
42
|
+
/** EW update: weight of the newest action vs. the running score. */
|
|
43
|
+
export declare const EW_ALPHA = 0.2;
|
|
44
|
+
export interface BehavioralSignalInput {
|
|
45
|
+
classification: string | null;
|
|
46
|
+
/** From buyer_inbox_sender_stats for this email's sender. */
|
|
47
|
+
senderStats?: SenderStats;
|
|
48
|
+
/** From buyer_inbox_threads for this email's thread. */
|
|
49
|
+
thread?: ThreadSignal;
|
|
50
|
+
/** Operator's explicit thumbs (buyer_inbox_importance_feedback), or null. */
|
|
51
|
+
explicitLabel?: "important" | "not" | null;
|
|
52
|
+
}
|
|
53
|
+
export interface BehavioralSignals {
|
|
54
|
+
/** Blend of category prior + per-sender learned score, in [0,100]. */
|
|
55
|
+
blendedScore: number;
|
|
56
|
+
/** The cold-start global prior used. */
|
|
57
|
+
prior: number;
|
|
58
|
+
/** The learned per-sender score (0 if cold). */
|
|
59
|
+
learnedScore: number;
|
|
60
|
+
/** How much weight the learned score got (0..1), grows with action count. */
|
|
61
|
+
learnedWeight: number;
|
|
62
|
+
/** Recency strength of the last correspondence (0..1). */
|
|
63
|
+
recencyStrength: number;
|
|
64
|
+
/** Derived sender reply rate (0..1) — strongest social signal. */
|
|
65
|
+
replyRate: number;
|
|
66
|
+
/** The named contributions actually applied, for explainability. */
|
|
67
|
+
contributions: BehavioralContribution[];
|
|
68
|
+
/** Final bounded point bonus the content scorer should ADD. */
|
|
69
|
+
pointBonus: number;
|
|
70
|
+
/** Did an explicit operator override fire? */
|
|
71
|
+
explicitOverride: "important" | "not" | null;
|
|
72
|
+
}
|
|
73
|
+
export interface BehavioralContribution {
|
|
74
|
+
signal: string;
|
|
75
|
+
/** Plain-English driver, e.g. "Replies to this sender 80% of the time". */
|
|
76
|
+
label: string;
|
|
77
|
+
/** Points contributed to pointBonus (can be negative). */
|
|
78
|
+
points: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Recency strength of last correspondence: 1.0 if within RECENCY_FULL_DAYS,
|
|
82
|
+
* decaying linearly to 0.5 at RECENCY_HALF_DAYS, then 0.5→0 out to 2×. A
|
|
83
|
+
* recent correspondent matters more than a year-stale one.
|
|
84
|
+
*/
|
|
85
|
+
export declare function recencyStrength(lastCorrespondedAt: string | Date | null, now: Date): number;
|
|
86
|
+
/**
|
|
87
|
+
* Blend the global category prior with the per-sender learned score, weighted
|
|
88
|
+
* by how much history we have (the n-gated cold-start discipline). With 0
|
|
89
|
+
* actions the prior fully dominates; at LEARN_KNEE actions the learned score
|
|
90
|
+
* is fully trusted. This IS the Gmail global-prior + per-user-correction blend.
|
|
91
|
+
*/
|
|
92
|
+
export declare function blendLearnedScore(prior: number, stats: SenderStats): {
|
|
93
|
+
blended: number;
|
|
94
|
+
learnedWeight: number;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Compute the explainable behavioral signal bundle for one email. The caller
|
|
98
|
+
* passes the per-sender stats + thread features it loaded; this is pure math.
|
|
99
|
+
*
|
|
100
|
+
* The point bonus is the bounded amount the content scorer should ADD so a
|
|
101
|
+
* behaviorally-important-but-content-quiet email (the replied-to chatty vendor)
|
|
102
|
+
* can climb out of 'low'. It is HARD-CAPPED at BEHAVIOR_MAX_POINTS and never
|
|
103
|
+
* touches the regulatory floor (recall/WSLCB are scored before behavior).
|
|
104
|
+
*/
|
|
105
|
+
export declare function computeBehavioralSignals(e: BehavioralSignalInput, now: Date): BehavioralSignals;
|
|
106
|
+
export type SenderAction = "reply" | "open" | "pullback" | "do" | "flag" | "archive_unread" | "digest_without_open" | "delete";
|
|
107
|
+
/**
|
|
108
|
+
* Apply one operator action to a sender's running stats. EW-updates the
|
|
109
|
+
* learned_score toward the action's implied target, increments the relevant
|
|
110
|
+
* counter, and stamps recency. Bounded step (EW_ALPHA) so no single action
|
|
111
|
+
* lurches the score; recent behavior dominates over time.
|
|
112
|
+
*
|
|
113
|
+
* Cold start: the FIRST action seeds the learned_score from the category prior
|
|
114
|
+
* (passed in) so the running score never starts at a meaningless 0.
|
|
115
|
+
*/
|
|
116
|
+
export declare function updateSenderStats(prev: SenderStats, action: SenderAction, classification: string | null, at: string | Date, alpha?: number): SenderStats;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// PORTED VERBATIM (pure, no-DB) from the RadMail main app:
|
|
3
|
+
// /Users/GreenLife/Documents/CODE/RadMail/src/lib/importance/signals.ts
|
|
4
|
+
// Behavioral-signal dependency of the importance scorer. Recovered into
|
|
5
|
+
// radmail-mcp so the MCP sandbox runs the SAME deterministic math as production.
|
|
6
|
+
// Keep byte-for-byte with source.
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// Importance BEHAVIORAL SIGNALS — pure-fn lib. Ported AS-IS from the source
|
|
9
|
+
// engine's buyer-inbox-importance-signals.ts (architecture §4). No tenant
|
|
10
|
+
// surgery needed — this layer keys on per-sender stats (loaded per-org by the
|
|
11
|
+
// caller), not on a vendor/store FK, so the math ports byte-for-byte.
|
|
12
|
+
//
|
|
13
|
+
// WHY THIS LAYER EXISTS: the content scorer (score.ts) is a pure additive sum of
|
|
14
|
+
// CONTENT signals (class, $, due-date) with NO behavioral signal — so a chatty
|
|
15
|
+
// counterparty email the owner REPLIED to, a paid invoice that got `processed`,
|
|
16
|
+
// or a recurring correspondent whose mail always matters all sink to 'low'.
|
|
17
|
+
// Gmail Priority Inbox's lesson: importance = predicted probability the user
|
|
18
|
+
// ACTS, learned from sender behavior, with a global prior to beat cold-start and
|
|
19
|
+
// a per-(org,sender) correction layer, optimized so FALSE-NEGATIVES (a buried
|
|
20
|
+
// important email) are rare. This file computes that behavioral layer — every
|
|
21
|
+
// signal is a named number you can read. No black box.
|
|
22
|
+
//
|
|
23
|
+
// CAN'T RUN AWAY: (1) the learned per-sender score is BLENDED toward, gated by
|
|
24
|
+
// action-count, so a brand-new sender can't swing the score; (2) the total
|
|
25
|
+
// behavioral contribution is HARD-CAPPED (BEHAVIOR_MAX_POINTS) — behavior can
|
|
26
|
+
// lift a buried-but-real email out of 'low' but can never manufacture a
|
|
27
|
+
// 'critical' or bury a recall; (3) the EW update step is bounded + recency-
|
|
28
|
+
// weighted. PURE. No DB, no network, no clock-of-its-own. Fully unit-pinned.
|
|
29
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
30
|
+
// ─── Global category priors (cold-start, research brief §2.3 step 1) ──────
|
|
31
|
+
// The "global model": a hand-set behavioral prior per class on a 0–100 scale,
|
|
32
|
+
// representing "how likely is a typical email of this class to be acted on."
|
|
33
|
+
// This gives sane behavior on day one before any per-sender history exists.
|
|
34
|
+
// These are LEARNED-LAYER priors (P(act)), distinct from the content scorer's
|
|
35
|
+
// point values — they seed the per-sender learned score, they don't replace
|
|
36
|
+
// the regulatory content scoring.
|
|
37
|
+
export const CATEGORY_PRIORS = {
|
|
38
|
+
recall: 95,
|
|
39
|
+
wslcb_notice: 95,
|
|
40
|
+
invoice: 85,
|
|
41
|
+
po_confirmation: 70,
|
|
42
|
+
coa: 65,
|
|
43
|
+
shipping: 45,
|
|
44
|
+
other: 40,
|
|
45
|
+
unclassified: 40,
|
|
46
|
+
meeting: 35,
|
|
47
|
+
availability: 18,
|
|
48
|
+
sample: 15,
|
|
49
|
+
marketing: 10,
|
|
50
|
+
system: 10,
|
|
51
|
+
};
|
|
52
|
+
export const DEFAULT_CATEGORY_PRIOR = 40;
|
|
53
|
+
export function categoryPrior(classification) {
|
|
54
|
+
if (!classification)
|
|
55
|
+
return DEFAULT_CATEGORY_PRIOR;
|
|
56
|
+
return CATEGORY_PRIORS[classification.toLowerCase()] ?? DEFAULT_CATEGORY_PRIOR;
|
|
57
|
+
}
|
|
58
|
+
/** A fresh, never-seen sender (cold start). */
|
|
59
|
+
export function emptySenderStats() {
|
|
60
|
+
return {
|
|
61
|
+
emailCount: 0,
|
|
62
|
+
replyCount: 0,
|
|
63
|
+
openCount: 0,
|
|
64
|
+
archivedUnreadCount: 0,
|
|
65
|
+
pullbackCount: 0,
|
|
66
|
+
learnedScore: 0,
|
|
67
|
+
lastCorrespondedAt: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function emptyThreadSignal() {
|
|
71
|
+
return { userInThread: false, isReplyToUserOutbound: false, threadDepth: 0 };
|
|
72
|
+
}
|
|
73
|
+
// ─── Tuning constants (PIN-TESTED) ────────────────────────────────────────
|
|
74
|
+
/** Action-count at which the learned per-sender score is fully trusted. */
|
|
75
|
+
export const LEARN_KNEE = 5;
|
|
76
|
+
/** Recency: behavior within this many days is "fresh" (full strength). */
|
|
77
|
+
export const RECENCY_FULL_DAYS = 14;
|
|
78
|
+
/** Recency fully decays to half-strength by this horizon. */
|
|
79
|
+
export const RECENCY_HALF_DAYS = 60;
|
|
80
|
+
/** Hard cap on total points behavior can ADD to the content score. The cap is
|
|
81
|
+
* generous enough that a reliably-replied, recent correspondent (the buried-
|
|
82
|
+
* recall case) clears the 'high' band off a near-zero content base, but small
|
|
83
|
+
* enough that behavior can never manufacture a 'critical' (≥80) on its own. */
|
|
84
|
+
export const BEHAVIOR_MAX_POINTS = 42;
|
|
85
|
+
/** EW update: weight of the newest action vs. the running score. */
|
|
86
|
+
export const EW_ALPHA = 0.2;
|
|
87
|
+
function clamp(n, lo, hi) {
|
|
88
|
+
return Math.max(lo, Math.min(hi, n));
|
|
89
|
+
}
|
|
90
|
+
function round1(n) {
|
|
91
|
+
return Math.round(n * 10) / 10;
|
|
92
|
+
}
|
|
93
|
+
function toDate(v) {
|
|
94
|
+
if (v == null)
|
|
95
|
+
return null;
|
|
96
|
+
if (v instanceof Date)
|
|
97
|
+
return isNaN(v.getTime()) ? null : v;
|
|
98
|
+
const d = new Date(v);
|
|
99
|
+
return isNaN(d.getTime()) ? null : d;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Recency strength of last correspondence: 1.0 if within RECENCY_FULL_DAYS,
|
|
103
|
+
* decaying linearly to 0.5 at RECENCY_HALF_DAYS, then 0.5→0 out to 2×. A
|
|
104
|
+
* recent correspondent matters more than a year-stale one.
|
|
105
|
+
*/
|
|
106
|
+
export function recencyStrength(lastCorrespondedAt, now) {
|
|
107
|
+
const last = toDate(lastCorrespondedAt);
|
|
108
|
+
if (!last)
|
|
109
|
+
return 0;
|
|
110
|
+
const ageDays = (now.getTime() - last.getTime()) / DAY_MS;
|
|
111
|
+
if (ageDays <= RECENCY_FULL_DAYS)
|
|
112
|
+
return 1;
|
|
113
|
+
if (ageDays <= RECENCY_HALF_DAYS) {
|
|
114
|
+
const span = RECENCY_HALF_DAYS - RECENCY_FULL_DAYS;
|
|
115
|
+
return clamp(1 - 0.5 * ((ageDays - RECENCY_FULL_DAYS) / span), 0.5, 1);
|
|
116
|
+
}
|
|
117
|
+
const span = RECENCY_HALF_DAYS; // 60→120 days fades the last half to 0
|
|
118
|
+
return clamp(0.5 - 0.5 * ((ageDays - RECENCY_HALF_DAYS) / span), 0, 0.5);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Blend the global category prior with the per-sender learned score, weighted
|
|
122
|
+
* by how much history we have (the n-gated cold-start discipline). With 0
|
|
123
|
+
* actions the prior fully dominates; at LEARN_KNEE actions the learned score
|
|
124
|
+
* is fully trusted. This IS the Gmail global-prior + per-user-correction blend.
|
|
125
|
+
*/
|
|
126
|
+
export function blendLearnedScore(prior, stats) {
|
|
127
|
+
const actions = stats.replyCount + stats.openCount + stats.pullbackCount
|
|
128
|
+
+ stats.archivedUnreadCount;
|
|
129
|
+
const learnedWeight = clamp(actions / LEARN_KNEE, 0, 1);
|
|
130
|
+
const blended = prior * (1 - learnedWeight) + stats.learnedScore * learnedWeight;
|
|
131
|
+
return { blended: round1(clamp(blended, 0, 100)), learnedWeight: round1(learnedWeight) };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Compute the explainable behavioral signal bundle for one email. The caller
|
|
135
|
+
* passes the per-sender stats + thread features it loaded; this is pure math.
|
|
136
|
+
*
|
|
137
|
+
* The point bonus is the bounded amount the content scorer should ADD so a
|
|
138
|
+
* behaviorally-important-but-content-quiet email (the replied-to chatty vendor)
|
|
139
|
+
* can climb out of 'low'. It is HARD-CAPPED at BEHAVIOR_MAX_POINTS and never
|
|
140
|
+
* touches the regulatory floor (recall/WSLCB are scored before behavior).
|
|
141
|
+
*/
|
|
142
|
+
export function computeBehavioralSignals(e, now) {
|
|
143
|
+
const stats = e.senderStats ?? emptySenderStats();
|
|
144
|
+
const thread = e.thread ?? emptyThreadSignal();
|
|
145
|
+
const prior = categoryPrior(e.classification);
|
|
146
|
+
const { blended, learnedWeight } = blendLearnedScore(prior, stats);
|
|
147
|
+
const rec = round1(recencyStrength(stats.lastCorrespondedAt, now));
|
|
148
|
+
const replyRate = stats.emailCount > 0
|
|
149
|
+
? round1(stats.replyCount / stats.emailCount)
|
|
150
|
+
: 0;
|
|
151
|
+
const contributions = [];
|
|
152
|
+
let bonus = 0;
|
|
153
|
+
// ── Social: sender reply-rate × recency (strongest signal). A sender Doug
|
|
154
|
+
// reliably replies to, recently, is one whose mail should surface. ──
|
|
155
|
+
if (stats.emailCount > 0 && replyRate > 0) {
|
|
156
|
+
const pts = round1(replyRate * rec * 24);
|
|
157
|
+
if (pts > 0) {
|
|
158
|
+
bonus += pts;
|
|
159
|
+
contributions.push({
|
|
160
|
+
signal: "sender_reply_rate",
|
|
161
|
+
label: `You reply to this sender ${Math.round(replyRate * 100)}% of the time`,
|
|
162
|
+
points: pts,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ── Social: pull-backs from the digest are an explicit "you were wrong,
|
|
167
|
+
// this matters" correction — the strongest behavioral positive. ──
|
|
168
|
+
if (stats.pullbackCount > 0) {
|
|
169
|
+
const pts = round1(Math.min(stats.pullbackCount, 3) * 4 * rec);
|
|
170
|
+
if (pts > 0) {
|
|
171
|
+
bonus += pts;
|
|
172
|
+
contributions.push({
|
|
173
|
+
signal: "sender_pullback",
|
|
174
|
+
label: `You've rescued this sender from the digest ${stats.pullbackCount}×`,
|
|
175
|
+
points: pts,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ── Social: archived-unread rate is a negative signal — a sender whose mail
|
|
180
|
+
// you sweep away unread should NOT be lifted. ──
|
|
181
|
+
if (stats.emailCount >= LEARN_KNEE) {
|
|
182
|
+
const archiveRate = stats.archivedUnreadCount / stats.emailCount;
|
|
183
|
+
if (archiveRate >= 0.6) {
|
|
184
|
+
const pts = -round1(archiveRate * 8);
|
|
185
|
+
bonus += pts;
|
|
186
|
+
contributions.push({
|
|
187
|
+
signal: "sender_archive_unread",
|
|
188
|
+
label: `You usually sweep this sender away unread (${Math.round(archiveRate * 100)}%)`,
|
|
189
|
+
points: pts,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ── Thread: replying to a user's outbound closes a waiting-on item — high
|
|
194
|
+
// importance (the vendor finally answered). ──
|
|
195
|
+
if (thread.isReplyToUserOutbound) {
|
|
196
|
+
const pts = 16;
|
|
197
|
+
bonus += pts;
|
|
198
|
+
contributions.push({
|
|
199
|
+
signal: "reply_to_outbound",
|
|
200
|
+
label: "Replies to a message you sent (closes a waiting-on)",
|
|
201
|
+
points: pts,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else if (thread.userInThread) {
|
|
205
|
+
const pts = 7;
|
|
206
|
+
bonus += pts;
|
|
207
|
+
contributions.push({
|
|
208
|
+
signal: "user_in_thread",
|
|
209
|
+
label: "You're already part of this thread",
|
|
210
|
+
points: pts,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
// ── Learned per-sender lift: when history says this sender's mail gets
|
|
214
|
+
// acted on ABOVE its class prior, lift toward the learned score —
|
|
215
|
+
// weighted by how much history we trust. ──
|
|
216
|
+
if (learnedWeight > 0 && blended > prior) {
|
|
217
|
+
const pts = round1((blended - prior) / 100 * 22 * learnedWeight);
|
|
218
|
+
if (pts > 0) {
|
|
219
|
+
bonus += pts;
|
|
220
|
+
contributions.push({
|
|
221
|
+
signal: "learned_sender_score",
|
|
222
|
+
label: `History says this sender's mail matters (learned ${Math.round(stats.learnedScore)} vs prior ${Math.round(prior)})`,
|
|
223
|
+
points: pts,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ── Hard cap: behavior can lift, never run away. ──
|
|
228
|
+
const pointBonus = round1(clamp(bonus, -BEHAVIOR_MAX_POINTS, BEHAVIOR_MAX_POINTS));
|
|
229
|
+
return {
|
|
230
|
+
blendedScore: blended,
|
|
231
|
+
prior,
|
|
232
|
+
learnedScore: round1(stats.learnedScore),
|
|
233
|
+
learnedWeight,
|
|
234
|
+
recencyStrength: rec,
|
|
235
|
+
replyRate,
|
|
236
|
+
contributions,
|
|
237
|
+
pointBonus,
|
|
238
|
+
explicitOverride: e.explicitLabel ?? null,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/** The target action-likelihood each action implies (0..100). */
|
|
242
|
+
const ACTION_TARGET = {
|
|
243
|
+
reply: 100,
|
|
244
|
+
do: 100,
|
|
245
|
+
pullback: 95,
|
|
246
|
+
flag: 90,
|
|
247
|
+
open: 65,
|
|
248
|
+
archive_unread: 5,
|
|
249
|
+
digest_without_open: 10,
|
|
250
|
+
delete: 0,
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Apply one operator action to a sender's running stats. EW-updates the
|
|
254
|
+
* learned_score toward the action's implied target, increments the relevant
|
|
255
|
+
* counter, and stamps recency. Bounded step (EW_ALPHA) so no single action
|
|
256
|
+
* lurches the score; recent behavior dominates over time.
|
|
257
|
+
*
|
|
258
|
+
* Cold start: the FIRST action seeds the learned_score from the category prior
|
|
259
|
+
* (passed in) so the running score never starts at a meaningless 0.
|
|
260
|
+
*/
|
|
261
|
+
export function updateSenderStats(prev, action, classification, at, alpha = EW_ALPHA) {
|
|
262
|
+
const seeded = prev.emailCount === 0 && prev.learnedScore === 0
|
|
263
|
+
? categoryPrior(classification)
|
|
264
|
+
: prev.learnedScore;
|
|
265
|
+
const target = ACTION_TARGET[action];
|
|
266
|
+
const nextLearned = round1(clamp(seeded * (1 - alpha) + target * alpha, 0, 100));
|
|
267
|
+
const next = {
|
|
268
|
+
...prev,
|
|
269
|
+
learnedScore: nextLearned,
|
|
270
|
+
lastCorrespondedAt: at,
|
|
271
|
+
};
|
|
272
|
+
// Each action implies an inbound email was processed → bump the denominator
|
|
273
|
+
// exactly once per action (an action is "what happened to one email").
|
|
274
|
+
next.emailCount = prev.emailCount + 1;
|
|
275
|
+
if (action === "reply" || action === "do")
|
|
276
|
+
next.replyCount = prev.replyCount + 1;
|
|
277
|
+
if (action === "open" || action === "reply" || action === "do" || action === "flag") {
|
|
278
|
+
next.openCount = prev.openCount + 1;
|
|
279
|
+
}
|
|
280
|
+
if (action === "pullback")
|
|
281
|
+
next.pullbackCount = prev.pullbackCount + 1;
|
|
282
|
+
if (action === "archive_unread" || action === "digest_without_open") {
|
|
283
|
+
next.archivedUnreadCount = prev.archivedUnreadCount + 1;
|
|
284
|
+
}
|
|
285
|
+
return next;
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../../../src/engine/signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const COMMITMENT_DIRECTIONS: readonly ["owed_by_us", "owed_to_us"];
|
|
2
|
+
export type CommitmentDirection = (typeof COMMITMENT_DIRECTIONS)[number];
|
|
3
|
+
export declare const COMMITMENT_ACTION_TYPES: readonly ["send_deliverable", "follow_up", "contact_third_party", "answer_question", "payment", "decision", "other"];
|
|
4
|
+
export type CommitmentActionType = (typeof COMMITMENT_ACTION_TYPES)[number];
|
|
5
|
+
export declare function isCommitmentActionType(v: string): v is CommitmentActionType;
|
|
6
|
+
/** Coerce an arbitrary LLM-returned action_type to the closed enum (unknown → 'other'). */
|
|
7
|
+
export declare function coerceActionType(v: unknown): CommitmentActionType;
|
|
8
|
+
export declare const COMMITMENT_STATES: readonly ["detected", "confirmed", "needs_due_date", "scheduled", "drafted", "sent", "done", "overdue", "escalated", "dismissed", "snoozed", "cancelled"];
|
|
9
|
+
export type CommitmentState = (typeof COMMITMENT_STATES)[number];
|
|
10
|
+
export declare const SLA_BASES: readonly ["explicit", "relative", "default_by_type", "manual"];
|
|
11
|
+
export type SlaBasis = (typeof SLA_BASES)[number];
|
|
12
|
+
export type ExtractedCommitment = {
|
|
13
|
+
direction: CommitmentDirection;
|
|
14
|
+
party: string;
|
|
15
|
+
action: string;
|
|
16
|
+
actionType: CommitmentActionType;
|
|
17
|
+
duePhrase: string | null;
|
|
18
|
+
confidence: number;
|
|
19
|
+
evidenceSpan: string;
|
|
20
|
+
};
|