/**
 * relayContentDedup — content-hash dedup for the agent-to-agent `relay-agent`
 * ingress path.
 *
 * The id-based dedup in MessageRouter.relay keys on `message.id`. That misses a
 * specific failure mode observed 2026-05-30: a SENDER whose HTTP call blocks on
 * the RECEIVER's session spawn (slow on a loaded box) times out, then RETRIES
 * the same message with a FRESH `message.id`. The retry slips past the id-based
 * dedup → the receiver spawns/resumes and replies twice (the duplicate-reply
 * bug — saw 6 doubled replies in one evening).
 *
 * This layer recognizes the retry by the STABLE triple
 * (senderAgent, threadId, normalized content) within a short window, regardless
 * of the message id. It is a bounded, in-memory, fixed-window dedup:
 *   - fresh (sender, thread, content) → process + record
 *   - identical within `ttlMs` of first-seen → drop (duplicate retry)
 *   - identical `ttlMs`+ after first-seen → process (plausibly a real re-send)
 *
 * Memory is bounded by `maxEntries` (oldest-evicted) plus a lazy sweep of
 * expired keys on each call. The window is intentionally short so it only ever
 * collapses true rapid retries, never two genuinely-distinct sends.
 */
export interface RelayContentDedupOpts {
    /** Window from first-seen during which an identical inbound is a duplicate. */
    ttlMs?: number;
    /** Hard cap on retained keys (oldest evicted past this). */
    maxEntries?: number;
    /** Injectable clock for deterministic tests. */
    now?: () => number;
}
export declare class RelayContentDedup {
    private readonly ttlMs;
    private readonly maxEntries;
    private readonly now;
    /** key -> firstSeen epoch ms (Map preserves insertion order for eviction). */
    private readonly seen;
    constructor(opts?: RelayContentDedupOpts);
    /** Stable dedup key for an inbound relay message. */
    static keyFor(senderAgent: string, threadId: string, content: string): string;
    /**
     * Returns true if this inbound should be processed (fresh, or the prior
     * sighting has aged past the window); false if it is a duplicate retry seen
     * within the window. Fresh keys are recorded. Safe to call on every inbound.
     */
    shouldProcess(senderAgent: string, threadId: string, content: string): boolean;
    /** Number of retained keys (test/observability aid). */
    size(): number;
    private sweep;
    private enforceCap;
}
//# sourceMappingURL=relayContentDedup.d.ts.map