/**
 * Asset caption + OCR service (P3b — indexing pillar).
 *
 * Turns an image asset's bytes into searchable text: a concise factual
 * description plus an OCR transcription of any legible text. The sweep
 * (asset-index-sweep.ts) stores that text in `assets.db.caption`, keyed by the
 * immutable assetId (asset-as-embed, decision D1 — DB column, no sidecar), and
 * folds it into the search text of every entry that embeds the image, so a
 * captioned image becomes findable by its content, not just its filename.
 *
 * This module owns ONLY the model call + the bounded fan-out. It does NOT touch
 * disk, git, or LanceDB — the sweep wires those so the service stays a pure,
 * unit-testable transform over `(bytes) → text`.
 *
 * Guardrails (decision A3 + Codex):
 *  - **Bounded concurrency** (default 2): vision is not a free background
 *    service; a bulk import / first-boot migration must not fan out unbounded.
 *  - **Per-call timeout**: a hung provider call can't wedge the pool.
 *  - **Retry cap → permanent `failed`**: transient errors retry up to a cap,
 *    then the asset is honestly marked filename-only.
 *  - **Failure isolation**: one image's failure never aborts the batch.
 *  - **Gateway degrade (option a)**: `completeSimple()` cannot reach the
 *    Studiograph Credits gateway (it routes through its own client), so in
 *    gateway mode captioning is skipped and the image stays honestly
 *    filename-only — NOT routed through the gateway here.
 */
/** Model coordinates resolved by the caller (orchestrator pattern). */
export interface CaptionModelConfig {
    provider: string;
    modelId: string;
    apiKey: string;
}
/** Outcome of a single caption attempt. */
export interface CaptionResult {
    /** `full` = caption text produced; `failed` = honest filename-only. */
    status: 'full' | 'failed';
    /** The caption + OCR text (present only when status === 'full'). */
    text?: string;
    /** Machine-readable reason when failed (gateway | no-vision | no-api-key | error | timeout | empty). */
    reason?: string;
}
/**
 * Minimal stand-in for pi-ai's `completeSimple`. Injectable so tests exercise
 * the retry / timeout / concurrency logic without a live provider.
 */
export type CaptionCompleteFn = (model: unknown, context: unknown, options: {
    apiKey: string;
    maxTokens?: number;
}) => Promise<{
    content: Array<{
        type: string;
        text?: string;
    }>;
    stopReason?: string;
    errorMessage?: string;
}>;
export interface CaptionOptions {
    /** Per-call wall-clock budget. Default 60s. */
    timeoutMs?: number;
    /** Total attempts per image (initial + retries). Default 2. */
    maxAttempts?: number;
    /** Max caption tokens. Default 1024. */
    maxTokens?: number;
    /** Bytes above which the image is skipped (filename-only) instead of sent. */
    maxBytes?: number;
    /** Override the model call (tests). Defaults to pi-ai `completeSimple`. */
    completeFn?: CaptionCompleteFn;
}
/** Bounded caption fan-out — vision is metered, keep it small (A3). */
export declare const DEFAULT_CAPTION_CONCURRENCY = 2;
/**
 * Is captioning reachable for this model config right now? Separate from
 * `supportsVision` because the gateway IS vision-capable yet unreachable via
 * `completeSimple` (decision A6 + the gateway-degrade note).
 */
export declare function canCaption(config: CaptionModelConfig): {
    ok: boolean;
    reason?: string;
};
/**
 * Caption + OCR a single image. Gated by `canCaption`; never throws — a
 * permanent failure resolves to `{ status: 'failed', reason }` so the caller
 * can record honest index state.
 */
export declare function captionImage(buffer: Buffer, mimeType: string, config: CaptionModelConfig, opts?: CaptionOptions): Promise<CaptionResult>;
/** One image to caption, paired with a caller-chosen key (e.g. entity id). */
export interface CaptionJob {
    key: string;
    buffer: Buffer;
    mimeType: string;
}
/** A caption result tagged with its job key. */
export interface CaptionBatchResult extends CaptionResult {
    key: string;
}
/**
 * Caption a batch of images with bounded concurrency and full failure
 * isolation — a single image throwing or timing out never sinks the batch.
 * Results come back in input order, each tagged with its job key.
 */
export declare function captionImages(jobs: CaptionJob[], config: CaptionModelConfig, opts?: CaptionOptions & {
    concurrency?: number;
}): Promise<CaptionBatchResult[]>;
