import type { ChunkOptions } from '../rag/chunk.js';
import type { VectorStore } from '../rag/vector-store.js';
import type { EmbeddingProvider } from '../spi/embedding-provider.js';
import { type UploadCompletePayload } from './media-events.js';
import { type TextExtractor } from './text-extractor.js';
/** The minimal, structural slice of an `@adonis-agora/media` disk this bridge reads bytes from. */
export interface DiskBytesReader {
    /** Return the object's raw bytes (a media disk's `getBytes(key)`). */
    getBytes(key: string): Promise<Uint8Array>;
}
/**
 * The minimal, structural slice of an `@adonis-agora/media` `MediaManager` this bridge needs — just
 * `disk(name)` yielding a {@link DiskBytesReader}. Structural typing keeps `@adonis-agora/media` an
 * OPTIONAL peer: nothing is imported from it, an app passes its live `MediaManager` (or any handle that
 * satisfies this shape) at wiring time.
 */
export interface MediaManagerHandle {
    disk(name?: string): DiskBytesReader;
}
/**
 * A media file to ingest. `id` becomes the RAG document id (chunk ids `${id}#<n>`); `disk`/`key` locate
 * the bytes through the {@link MediaManagerHandle}; `contentType` drives extractor dispatch. The owner /
 * tenant fields are optional and, when present, tag every chunk's metadata so retrieval can filter by
 * tenant/owner/collection.
 */
export interface MediaRef {
    id: string;
    disk: string;
    key: string;
    contentType: string;
    ownerType?: string;
    ownerId?: string;
    collection?: string;
    tenantRef?: string;
    /** Byte size, when known up front — used only by the `maxBytes` gate; the bytes are the source of truth. */
    size?: number;
}
export type MediaIngestSkipReason = 'unsupported-type' | 'too-large' | 'empty-text';
export type MediaIngestResult = {
    status: 'ingested';
    chunks: number;
} | {
    status: 'skipped';
    reason: MediaIngestSkipReason;
};
/** Turn an `upload.complete` diagnostics payload into an ingestable {@link MediaRef}, or `null` to skip. */
export type ResolveMediaRef = (payload: UploadCompletePayload) => MediaRef | null | Promise<MediaRef | null>;
/**
 * Everything the media→RAG bridge needs. Only `media`, `embedder`, and `store` are required; the
 * extractor defaults to {@link defaultTextExtractor} (text/*, JSON, HTML) so binary formats are skipped
 * rather than indexed as garbage. Register a PDF/DOCX parser on a {@link import('./text-extractor.js').MimeTextExtractor}
 * and pass it as `extractor` — the PDF library stays entirely on the host side (never a dependency here).
 */
export interface MediaRagIngestionConfig {
    /** The media handle bytes are read through (an `@adonis-agora/media` `MediaManager`, structurally typed). */
    media: MediaManagerHandle;
    /** Embeds each chunk. Pass the same {@link EmbeddingProvider} the agent's retriever uses. */
    embedder: EmbeddingProvider;
    /** The RAG vector store chunks are upserted into (the same store the retriever searches). */
    store: VectorStore;
    /** Bytes → text. Default {@link defaultTextExtractor}. Register a PDF/DOCX hook to widen it. */
    extractor?: TextExtractor;
    /**
     * Restrict ingestion to these content types (checked before the extractor). Omit/empty = every type
     * the extractor supports. A content type not in this allow-list is skipped as `unsupported-type`.
     */
    contentTypes?: string[];
    /** Chunking options forwarded to `chunkDocuments`. */
    chunk?: ChunkOptions;
    /** Skip (don't read) files larger than this many bytes (checked against `ref.size` when present). */
    maxBytes?: number;
    /**
     * Resolve an `upload.complete` diagnostics payload (`{ id, disk, key }`) into a full {@link MediaRef}
     * — the seam the auto-subscriber needs, since the event carries no content-type or owner metadata.
     * Required to call {@link MediaRagIngestion.subscribe}; return `null` to skip an event.
     */
    resolve?: ResolveMediaRef;
}
/** Thrown by {@link MediaRagIngestion.subscribe} when no `resolve` seam was configured. */
export declare class MediaRagResolveRequiredError extends Error {
    constructor();
}
/**
 * Bridges `@adonis-agora/media` uploads into the agent's RAG stack: fetch the bytes → extract text by
 * content type → chunk → embed → upsert into the configured {@link VectorStore}, tagging every chunk
 * with `{ mediaId, ownerType, ownerId, collection, tenantRef }` so retrieval can be scoped per
 * tenant/owner/collection. Two triggers, both opt-in and no-op until wired:
 *
 * - {@link ingestMedia} — call it explicitly with a {@link MediaRef} (e.g. from your own upload flow).
 * - {@link subscribe} — subscribe to the media library's `agora:media:upload.complete` diagnostics
 *   channel and auto-ingest each finished upload (needs a `resolve` seam).
 *
 * Everything is structural: no import of `@adonis-agora/media`, and `node:diagnostics_channel` is a
 * Node builtin, so there is no hard dependency on `@adonis-agora/diagnostics` for the subscribe path.
 */
export declare class MediaRagIngestion {
    private readonly config;
    private readonly extractor;
    private readonly contentTypes;
    private readonly inFlight;
    private teardown;
    constructor(config: MediaRagIngestionConfig);
    /**
     * Ingest one media file: content-type filter → size gate → read bytes → extract → remove-then-chunk
     * → embed → upsert. Unsupported/oversized/empty files are skipped (not errors). Chunk metadata carries
     * `{ mediaId, ownerType, ownerId, collection, tenantRef }` (only the fields present on `ref`).
     */
    ingestMedia(ref: MediaRef): Promise<MediaIngestResult>;
    /** Drop a media document's chunks from the vector store — the delete half of keeping RAG in sync. */
    removeMedia(mediaId: string): Promise<void>;
    /**
     * Guard + resolve + ingest one `upload.complete` diagnostics payload. Public so a caller can await it
     * directly (deterministic tests) instead of going through the subscription. A no-op when `resolve`
     * isn't configured, the payload isn't a valid `upload.complete`, or `resolve` returns `null`.
     */
    handleUploadComplete(payload: unknown): Promise<MediaIngestResult | undefined>;
    /**
     * Subscribe to the media library's `agora:media:upload.complete` channel and auto-ingest each finished
     * upload. Idempotent (a second call is a no-op while already subscribed). Returns — and stores — an
     * unsubscribe function; ingestion errors are caught and published on `agora:rag:media.failed` so a bad
     * file never breaks the channel. Requires a `resolve` seam ({@link MediaRagResolveRequiredError}).
     */
    subscribe(): () => void;
    /** Unsubscribe from the media channel (if subscribed) and await every in-flight auto-ingestion. */
    unsubscribe(): Promise<void>;
    /** Await every in-flight auto-ingestion — for graceful shutdown and deterministic tests. */
    settle(): Promise<void>;
    /** Whether the auto-subscriber is currently attached to the media channel. */
    get subscribed(): boolean;
    /** Handle one channel event with the same error boundary the subscriber uses. */
    private ingestFromEvent;
    private track;
}
/**
 * Build a media→RAG ingestion bridge (idiomatic factory). Wire it in a provider's `boot()`:
 *
 * ```ts
 * import { mediaRagIngestion } from '@adonis-agora/agent/rag-media'
 *
 * const ingestion = mediaRagIngestion({
 *   media: await app.container.make('media.manager'),
 *   embedder: myEmbedder,
 *   store: myVectorStore,
 *   contentTypes: ['text/plain', 'text/markdown', 'application/pdf'],
 *   extractor: defaultTextExtractor().register('application/pdf', myPdfExtractor),
 *   resolve: async ({ id, disk, key }) => lookupMediaRecord(id), // → MediaRef
 * })
 * const off = ingestion.subscribe() // auto-ingest on upload.complete
 * ```
 *
 * Or trigger it explicitly: `await ingestion.ingestMedia(ref)`. Everything is opt-in and no-op until
 * wired — nothing runs, subscribes, or imports the media/pdf peers unless you call it.
 */
export declare function mediaRagIngestion(config: MediaRagIngestionConfig): MediaRagIngestion;
//# sourceMappingURL=media-rag-ingestion.d.ts.map