import type { MemoryWriteScope } from "../memory-backend/global-scope.js"; import { type HindsightClientApi } from "./client.js"; export interface RetainInput { content: string; context?: string; scope?: MemoryWriteScope; } /** A published event file. Never rewritten, so its mtime is its enqueue time. */ export interface OutboxEvent { version: 1; /** Also the server `document_id`, so a resend replaces instead of duplicating. */ id: string; scope: MemoryWriteScope; tags: string[]; timestamp: string; content: string; context: string; sessionId: string; } export interface RetainCall { sessionId: string; toolCallId: string; /** Context for items without their own. */ context: string; /** Tags of project-scoped items; global items are retained untagged. */ tags: string[] | undefined; } export interface DrainResult { /** Another holder is draining this destination, or an enqueue is mid-batch; nothing was sent. */ busy: boolean; delivered: number; /** Events refused by the server, malformed, or past their TTL, across all destinations. */ quarantined: number; /** Set when a retryable failure stopped delivery; `kept` events remain for retry. */ error?: string; kept: number; } export interface HindsightOutboxOptions { agentDir: string; apiUrl: string; bankId: string; apiToken: string | null; client: HindsightClientApi; ensureBank: () => Promise; } /** * Durable queue of tool-initiated retains: one immutable file per memory under * `/hindsight-outbox//`. A 2xx response deletes the event; it * means server acceptance, not completed extraction. * * Concurrency: a per-destination queue lock serializes capacity checks and * publication, and the drainer takes it for the instant it lists and reads * events, so a snapshot never lands inside a batch that may still roll back; a * per-destination drain lease, released by the OS when its process exits, lets * exactly one holder send and delete events. Event files are never rewritten, * so writers and the drainer never contend for one file. */ export declare class HindsightOutbox { #private; constructor(options: HindsightOutboxOptions); /** Where refused, malformed, and expired events go for review. */ get quarantineDir(): string; /** * Persists one tool call's items, all or none, before resolving. Returns how many * events are new: a retried call has the same ids and publishes nothing again. */ enqueue(call: RetainCall, items: RetainInput[]): Promise; /** * Sends this destination's events and quarantines every destination's expired * ones, then prunes quarantine. Stops at the first retryable failure; events stay * on disk for the next drain. Pruning is best-effort and never fails delivery. */ drain(): Promise; }