/**
 * The USER-ATTACHMENT SEAT — the one road a file the user hands the model takes:
 *
 *   the host declares it on the objective (`TaskSpec.userAttachments`) → the engine screens the declaration at the
 *   door → after the UserPromptSubmit hook lets the objective through, the engine reads a path entry with the Read
 *   tool's own read (`ModelFileReader.readForModel`) under the run's synthetic-Read judge, or takes the host's bytes →
 *   it mints ONE message per attachment that trails the human message: an engine note whose marked blocks hold only
 *   static sentences and whose data (the name or path, then the contents or the refusal) sits between them → the
 *   message's delivery record (`UserMessage.attachment`) is the one source of "what was delivered".
 *
 * This module owns the three steps no other module may repeat: the screen (`screenUserAttachments`), the mint
 * (`readUserAttachments` → the frame seeds, the `human_input` projection and the pending commits) and the settlement
 * (`createAttachmentDelivery`: a read's effects commit when its frame reaches the transcript, keyed by
 * `(inputId, ordinal)` — never at read time, never by text).
 *
 * The frame, per attachment (blocks in order):
 *   <system-reminder mark="…">\n<opening sentence>\n</system-reminder>\n     — static, the attachment's number only
 *   Path: "<declared path>"\n   or   Name: "<name>"\n                           — data (lossless quoted label)
 *   <data blocks>                                                             — the file's own blocks / the refusal
 *   \n\n<system-reminder mark="…">\n<note sentence>\n</system-reminder>      — one per engine note, static
 *   \n\n<system-reminder mark="…">\nEnd of attachment <n>.\n</system-reminder>
 * Every marked block after data opens after a blank line (`MARKED_BLOCK_AFTER_DATA`): the completions lanes join a
 * message's text blocks with no separator.
 */
import type { ImageContent, TextContent, UserAttachmentSupply, UserMessageAttachment } from "../internal/llm.js";
import type { HumanInputAttachment } from "./task-event.js";
import { type ModelFileReader } from "../tools/fs/fs-read.js";
import type { SyntheticReadJudge } from "./synthetic-read-verdict.js";
import { type ReminderDisclosureCounts } from "./reminder-disclosure.js";
import type { ContextWindowOverlay } from "./context-settings.js";
/** At most this many attachments on one objective. */
export declare const USER_ATTACHMENTS_MAX = 20;
/** The longest path or name an entry may carry (the platform path limit). */
export declare const USER_ATTACHMENT_LABEL_MAX = 4096;
/** What the engine found an attachment to be (an output, never declared): the Read lanes, a directory, host bytes. */
export declare const USER_ATTACHMENT_KINDS: readonly ["text", "notebook", "image", "pdf", "directory", "client_text", "client_image"];
/** Who held the bytes — the entry's arm. */
export declare const USER_ATTACHMENT_SUPPLIES: readonly ["path", "content_text", "content_image"];
/** What reached the model of an attachment's contents — the Read layer's own outcome words, the same frozen array. */
export declare const USER_ATTACHMENT_OUTCOMES: readonly ["attached", "partial", "unchanged", "not_attached"];
/**
 * The seat's capability descriptor — what a host reads to decide, per attachment, whether to declare it here: its kind
 * is in `kinds` and its arm in `supplies` ⇒ declare it on the objective; otherwise (a kind this seat does not carry, or
 * an engine without the descriptor) the host carries it some other way. `entries`: the objective only — a steer carries
 * no attachments (they go with the next objective).
 */
export declare const USER_ATTACHMENT_SEAT: Readonly<{
    entries: readonly ["objective"];
    kinds: readonly ["text", "notebook", "image", "pdf", "directory", "client_text", "client_image"];
    supplies: readonly ["path", "content_text", "content_image"];
    limits: Readonly<{
        maxEntries: 20;
        maxRenderedTextChars: 100000;
    }>;
}>;
/** One declaration as the door captured it: the caller's object read once, members copied. */
export type ScreenedUserAttachment = {
    readonly supply: "path";
    readonly path: string;
    readonly lines?: {
        readonly start: number;
        readonly end?: number;
    };
} | {
    readonly supply: "content_text";
    readonly name: string;
    readonly text: string;
    readonly startLine: number;
    readonly rendered: string;
} | {
    readonly supply: "content_image";
    readonly name: string;
    readonly data: string;
    readonly mimeType: string;
};
/**
 * The field a refusal names, as one value: `path` is the field path the sentence opens with, and `index` the attachment's
 * position in the seat (0-based, the `[i]` of that path) — present exactly when the sentence names one attachment; a refusal of
 * the seat as a whole (not a list, too many, a resume, the window) has no index. Built only by {@link SEAT_REF} /
 * {@link entryRef} / {@link memberRef}, so the index and the path can never name two attachments.
 */
export interface UserAttachmentFieldRef {
    readonly path: string;
    readonly index?: number;
}
/** The door's refusal: one code, the field named first in the sentence and again in `detail` ({@link UserAttachmentFieldRef}). */
export declare function userAttachmentRefusal(at: UserAttachmentFieldRef, problem: string): Error & {
    code: "config.user_attachment_invalid";
    detail: UserAttachmentFieldRef;
};
/**
 * The door: screen the seat's value (synchronous; the caller's object is read once, member by member, before the
 * first await of the run). `undefined` / an empty array ⇒ no attachments. `resumeLeg`: a durable resume mints no new
 * human message, so any entry there is refused. Throws `config.user_attachment_invalid` naming the field.
 */
export declare function screenUserAttachments(seat: unknown, opts: {
    resumeLeg: boolean;
}): readonly ScreenedUserAttachment[] | undefined;
/** A path entry on a run with no workspace: there is nothing the engine could read it from. */
export declare function refuseUserAttachmentPathsWithoutWorkspace(screened: readonly ScreenedUserAttachment[] | undefined): void;
/** One declared attachment as the UserPromptSubmit hook sees it (`UserPromptSubmitContext.userAttachments`). */
export interface UserAttachmentDeclaration {
    /** 1-based position among the objective's attachments. */
    readonly ordinal: number;
    /** Who holds the bytes: `path` (the engine reads it), `content_text` / `content_image` (the host sent them). */
    readonly supply: UserAttachmentSupply;
    readonly path?: string;
    readonly name?: string;
    /** A host entry's size in bytes (text as UTF-8, an image decoded). */
    readonly bytes?: number;
}
/** The UserPromptSubmit hook's view of the declarations. */
export declare function userAttachmentDeclarations(screened: readonly ScreenedUserAttachment[]): readonly UserAttachmentDeclaration[];
/**
 * The host images' byte admission — the one function an image the Read tool serves passes. Asynchronous (it decodes),
 * run on the captured values before any attachment is read or delivered. Throws `config.user_attachment_invalid`.
 */
export declare function admitUserAttachmentImages(screened: readonly ScreenedUserAttachment[]): Promise<ReadonlyMap<number, ImageContent>>;
/** One minted frame: the trailing message's seed, and the commit its delivery owes (absent ⇒ nothing to commit). */
export interface MintedAttachmentFrame {
    readonly seed: {
        readonly content: ReadonlyArray<TextContent | ImageContent>;
        readonly attachment: UserMessageAttachment;
    };
    readonly commit?: () => void;
}
export interface ReadUserAttachmentsInput {
    screened: readonly ScreenedUserAttachment[];
    /** The human input the attachments belong to (minted before the frames and the event, shared by both). */
    inputId: string;
    /** The leg's one file reader (absent on a run without a workspace — then only host entries exist). */
    reader: ModelFileReader | undefined;
    /** The run's synthetic-Read judge. */
    judge: SyntheticReadJudge;
    /** The admitted host images, by ordinal. */
    images: ReadonlyMap<number, ImageContent>;
    /** The tracked working directory a relative path resolves against (the Read tool's own). */
    cwd: string | undefined;
    mark: string | undefined;
    counts: ReminderDisclosureCounts | undefined;
    signal: AbortSignal;
}
/**
 * Read every declared attachment and mint its frame. Side-effect free toward the run: nothing is committed here — each
 * frame carries the commit its delivery owes, run only when the frame is in the transcript.
 */
export declare function readUserAttachments(input: ReadUserAttachmentsInput): Promise<MintedAttachmentFrame[]>;
/** The objective as the window check sees it: a reader of the live overlay over the model's window declarations (the
 *  same seat the request guard reads) and the objective text's length — it rides the first request ahead of the
 *  frames. The overlay is a GETTER because it is read when the frames exist, not when the call is made: the reads are
 *  asynchronous and a deployment may swap its window declarations meanwhile, as it may before any request. */
export interface AttachmentWindowInput {
    readonly overlay: () => ContextWindowOverlay | undefined;
    readonly objectiveChars: number;
}
/** The objective lane's read: once the UserPromptSubmit hook let the objective through (a blocked objective reads
 *  nothing), and before the pre-call gate, which prices the frames (`chars`). Refuses the whole objective when the frames
 *  and the objective cannot ride one request ({@link refuseFramesOverWindow}). Commits nothing. */
export declare function readObjectiveAttachments(prepared: Pick<import("./runner/contracts.js").Prepared, "userAttachments" | "modelFileReader" | "syntheticReadVerdict" | "cwdRef" | "reminderMark" | "reminderDisclosureCounts" | "abortController" | "harness">, inputId: string, blocked: boolean, window: AttachmentWindowInput): Promise<{
    frames: MintedAttachmentFrame[];
    chars: number;
}>;
/** The last attachment frame of the group the message `id` opens, or `id` when it has none (a `resumeAt` that keeps the
 *  message keeps its group). The frames of one input are appended one after another under its message (each the child of
 *  the one before), all carrying its input id. */
export declare function lastAttachmentFrameOf(entries: ReadonlyArray<{
    id: string;
    parentId: string | null;
    type: string;
    message?: unknown;
}>, id: string): string;
/** The `human_input` projection of the minted frames. */
export declare function humanInputAttachmentsOf(frames: readonly MintedAttachmentFrame[]): HumanInputAttachment[];
/**
 * The run's pending attachment commits, keyed by `(inputId, ordinal)`. A frame's commit runs exactly once, when the
 * harness reports that frame in the transcript; a frame that never got there (a refused pre-call budget, an abort, a
 * failed append) commits nothing — its entry is simply never settled.
 */
export interface AttachmentDelivery {
    /** Stage the minted frames of one input — called only once every gate before the append has passed. */
    stage(inputId: string, frames: readonly MintedAttachmentFrame[]): void;
    /** The frame `(inputId, ordinal)` is in the transcript: run its commit (once) and forget it. */
    settle(inputId: string, ordinal: number): void;
}
export declare function createAttachmentDelivery(): AttachmentDelivery;
