/**
 * recordingPack — a recording with every repeated value stored ONCE.
 *
 * Role:  Codec. `packRecording` turns a recording (`recordRun` ·
 *        `toRecording()`) into plain JSON data where a value the recording
 *        holds in more than one place is written once and referred to by its
 *        index everywhere else; `unpackRecording` turns it back. Nothing here
 *        runs, records or emits.
 * Reads: its argument.
 * Emits: N/A.
 *
 * ── WHY ─────────────────────────────────────────────────────────────────────
 * An agent's history is IN a recording once per place that saw it: each
 * iteration's slot subflows are seeded with the whole conversation, the
 * boundary log keeps each subflow's input and output, `iteration_end` carries
 * the history, every call re-announces the pieces in its context. So
 * iteration k writes the k results before it again, and plain JSON grows
 * with K²·R (K iterations, R-row results). Measured on an agent run with
 * 1,000-row tool results: 67 MB at 10 iterations, 808 MB at 40, and past
 * JSON's own string limit before 80 — the first result appeared 838 times at
 * K = 40. Each of those copies is the same value; packed, each is written
 * once and the recording grows with K·R.
 *
 * ── THE FORMAT ──────────────────────────────────────────────────────────────
 *   { format: 'agentfootprint.recording.packed.v1',
 *     values:    [ <value 0>, <value 1>, … ],   each written once
 *     recording: { snapshot, events, structure } with refs in place }
 *
 * A REF is the one-key object `{ "$af:ref": n }` — "values[n] goes here". A
 * value may hold refs to other values. A value is pooled when it occurs at
 * least twice and its JSON is at least {@link MIN_POOLED_CHARS} long; a value
 * that occurs once stays where it is, so a run with no repetition packs to
 * its plain JSON plus the envelope.
 *
 * ESCAPING keeps the mapping injective: an object of the recording's own that
 * has a key `"$af:ref"` or `"$af:esc"` is written as `{ "$af:esc": <it> }`, and
 * the reader takes what is inside literally. No recording can be mistaken for
 * a reference — pinned by test/recorders/observability/recordingPack.test.ts.
 *
 * ── THE LAW ─────────────────────────────────────────────────────────────────
 * `JSON.stringify(unpackRecording(JSON.parse(JSON.stringify(packRecording(r)))))`
 * is `toWireJson(r)`, byte for byte: packing follows `JSON.stringify` (each
 * `toJSON`, dropped `undefined`s and functions, `null` for non-finite numbers,
 * a cycle or a `BigInt` throws) and the wire rule for Errors
 * (`lib/wireJson.ts`) — the bytes a plain recording is minted as. Values are
 * read twice (once to count, once to write), so a getter that answers
 * differently on its second read decides what is written; a recording is
 * plain data, and reads the same both times.
 *
 * ── READING ONE ─────────────────────────────────────────────────────────────
 * `unpackRecording(value)` takes either shape: a packed recording is expanded,
 * anything else is returned as it is — so a reader that calls it reads every
 * recording ever minted, plain or packed. A pooled value expands to ONE object
 * shared by every place that referred to it (that is what keeps the expanded
 * recording linear in memory too): treat a recording as read-only, as every
 * viewer does. A `format` from this family that is not v1 is refused by name,
 * never half-read.
 */
import type { Recording } from './recordRun.js';
/** The format marker of a packed recording. */
export declare const PACKED_RECORDING_FORMAT = "agentfootprint.recording.packed.v1";
/**
 * The smallest JSON length a repeated value must have to be pooled. A
 * reference costs about 15 characters, so pooling anything shorter would make
 * a recording longer, not shorter.
 */
export declare const MIN_POOLED_CHARS = 64;
/** A recording with every repeated value written once — see the module header. */
export interface PackedRecording {
    readonly format: typeof PACKED_RECORDING_FORMAT;
    /** Every pooled value, each written once; referred to by its index. */
    readonly values: readonly unknown[];
    /** The recording, with each pooled value replaced by a reference. */
    readonly recording: unknown;
}
/** A packed recording this reader cannot expand — named, never half-read. */
export declare class PackedRecordingError extends Error {
    constructor(message: string);
}
/**
 * A packed recording whose PLAIN form is larger than the reader agreed to take
 * ({@link UnpackRecordingOptions.maxBytes}) — refused before anything is
 * expanded. Packed, a recording can stand for far more JSON than it holds (a
 * value referred to ten times, by values each referred to ten times, …), so
 * its own byte count bounds nothing a tree walk does with it; this does.
 */
export declare class PackedRecordingTooLargeError extends PackedRecordingError {
    /** The bound that was exceeded, in UTF-8 bytes of the plain recording's JSON. */
    readonly maxBytes: number;
    constructor(maxBytes: number);
}
/**
 * The default bound on what a packed recording may expand to: 512 MiB of JSON —
 * about the largest plain recording a JavaScript string can hold. Reading a
 * packed recording through the default is never more work than reading its
 * plain twin could have been.
 */
export declare const DEFAULT_UNPACK_MAX_BYTES: number;
/** How much a reader of {@link unpackRecording} agrees to expand. */
export interface UnpackRecordingOptions {
    /**
     * The largest PLAIN recording this read may stand for, in UTF-8 bytes of its
     * JSON — exactly the size the same recording minted plain would have.
     * Checked over the PACKED form, in time proportional to the packed size,
     * before anything is expanded; a packed recording over it is refused with
     * {@link PackedRecordingTooLargeError}. Default
     * {@link DEFAULT_UNPACK_MAX_BYTES}. `Infinity` takes anything — only for a
     * reader that trusts the recording and never walks it as a tree.
     */
    readonly maxBytes?: number;
}
/** Is `value` a packed recording of the format this reader expands? */
export declare function isPackedRecording(value: unknown): value is PackedRecording;
/**
 * Pack a recording so every repeated value is stored once.
 *
 * @throws TypeError where `JSON.stringify` throws — a cycle or a `BigInt`.
 *
 * @example
 * ```ts
 * import { packRecording, recordRun } from 'agentfootprint/observe';
 *
 * const recorder = recordRun(agent);
 * await agent.run({ message });
 * fs.writeFileSync('run.json', JSON.stringify(packRecording(recorder.toRecording())));
 * ```
 */
export declare function packRecording(recording: Recording): PackedRecording;
/**
 * @internal {@link packRecording}, counting its work: `work.members` grows by
 * one for every member value the packer reads, on both passes — the operation
 * count test/recorders/observability/recordingPack.test.ts pins (4× the
 * iterations, ~4× the reads). Not on any barrel.
 */
export declare function packCounted(recording: Recording, work: {
    members: number;
} | undefined): PackedRecording;
/**
 * Read a recording that may be packed: a packed recording is expanded, any
 * other value is returned as it is — so one call reads every recording, plain
 * or packed. See the module header for what "expanded" shares.
 *
 * BOUNDED. A packed recording is expanded only when its plain form is at most
 * `maxBytes` (default {@link DEFAULT_UNPACK_MAX_BYTES}) — measured over the
 * packed form, each pooled value sized once, before anything is built. A plain
 * recording is returned as it is: its size is the size of the text it was
 * parsed from, which its reader bounds before parsing.
 *
 * @throws PackedRecordingTooLargeError when the plain form is over `maxBytes`.
 * @throws PackedRecordingError for a packed format other than v1, or a packed
 *   value whose references do not resolve.
 *
 * @example
 * ```ts
 * import { unpackRecording } from 'agentfootprint/observe';
 * import { observeRecording } from 'agentfootprint-lens';
 *
 * const recording = unpackRecording(JSON.parse(text));   // plain or packed
 * const { recorder, runner } = observeRecording(recording);
 *
 * // A host that serves recordings to others bounds what one may stand for:
 * unpackRecording(JSON.parse(text), { maxBytes: 16 * 1024 * 1024 });
 * ```
 */
export declare function unpackRecording(input: unknown, options?: UnpackRecordingOptions): Recording;
/**
 * @internal {@link unpackRecording}, counting its work: `work.measured` grows
 * by one for every packed node the size check reads, `work.decoded` for every
 * node expanded — the operation counts
 * test/recorders/observability/recordingPack.test.ts pins (a refused
 * amplification reads the packed form once and expands nothing). Not on any
 * barrel.
 */
export declare function unpackCounted(input: unknown, options: UnpackRecordingOptions, work: UnpackWork | undefined): Recording;
/** @internal What {@link unpackCounted} counts. */
export interface UnpackWork {
    measured: number;
    decoded: number;
}
