Files
clawdbot/src/auto-reply/reply/inbound-dedupe.ts
2026-01-11 00:12:25 +01:00

53 lines
1.7 KiB
TypeScript

import { logVerbose, shouldLogVerbose } from "../../globals.js";
import { createDedupeCache, type DedupeCache } from "../../infra/dedupe.js";
import type { MsgContext } from "../templating.js";
const DEFAULT_INBOUND_DEDUPE_TTL_MS = 20 * 60_000;
const DEFAULT_INBOUND_DEDUPE_MAX = 5000;
const inboundDedupeCache = createDedupeCache({
ttlMs: DEFAULT_INBOUND_DEDUPE_TTL_MS,
maxSize: DEFAULT_INBOUND_DEDUPE_MAX,
});
const normalizeProvider = (value?: string | null) =>
value?.trim().toLowerCase() || "";
const resolveInboundPeerId = (ctx: MsgContext) =>
ctx.OriginatingTo ?? ctx.To ?? ctx.From ?? ctx.SessionKey;
export function buildInboundDedupeKey(ctx: MsgContext): string | null {
const provider = normalizeProvider(
ctx.OriginatingChannel ?? ctx.Provider ?? ctx.Surface,
);
const messageId = ctx.MessageSid?.trim();
if (!provider || !messageId) return null;
const peerId = resolveInboundPeerId(ctx);
if (!peerId) return null;
const sessionKey = ctx.SessionKey?.trim() ?? "";
const accountId = ctx.AccountId?.trim() ?? "";
const threadId =
typeof ctx.MessageThreadId === "number" ? String(ctx.MessageThreadId) : "";
return [provider, accountId, sessionKey, peerId, threadId, messageId]
.filter(Boolean)
.join("|");
}
export function shouldSkipDuplicateInbound(
ctx: MsgContext,
opts?: { cache?: DedupeCache; now?: number },
): boolean {
const key = buildInboundDedupeKey(ctx);
if (!key) return false;
const cache = opts?.cache ?? inboundDedupeCache;
const skipped = cache.check(key, opts?.now);
if (skipped && shouldLogVerbose()) {
logVerbose(`inbound dedupe: skipped ${key}`);
}
return skipped;
}
export function resetInboundDedupe(): void {
inboundDedupeCache.clear();
}