import type { Message } from "../llm/index.js";
import type { AgentMessage } from "../loop/types.js";
/**
 * design/388 A-18 — the FROZEN history table: tool names a persisted pre-rename transcript may still carry
 * (the upstream trio and the pre-CC-name core trio), mapped to the path access the live definition declares.
 * Never grows: a new name declares its access on the catalog instead. Registered with the name-table gate.
 */
export declare const DURABLE_HISTORY_NAMES: ReadonlyMap<string, "read" | "create" | "edit">;
/** File paths touched by a session branch or compaction range. */
export interface FileOperations {
    /** Files read but not necessarily modified. */
    read: Set<string>;
    /** Files written by full-file write operations. */
    written: Set<string>;
    /** Files modified by edit operations. */
    edited: Set<string>;
    /**
     * Cross-set touch order for modified files (written ∪ edited), oldest→newest — a re-touch moves
     * the path to the end (Set insertion-order semantics via delete-then-add). This is what lets
     * working-file attachments pick the MOST RECENTLY touched files instead of the first N
     * alphabetically (the LONGRUN-2b miss: orders.js sorted out of the top-3).
     */
    modifiedOrder: Set<string>;
}
/** Create an empty file-operation accumulator. */
export declare function createFileOps(): FileOperations;
/** Add file operations from assistant tool calls to an accumulator. */
export declare function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void;
/** One retained invoked skill: the Skill tool result text as it stood in context (possibly
 *  truncated with {@link SKILL_RETENTION_TRUNCATION_MARKER}). */
export interface InvokedSkillRetention {
    name: string;
    content: string;
}
/** Per-skill retained-content cap (chars; CC: 5000 tokens). Truncation is marker-inclusive: a
 *  truncated entry is EXACTLY this long, marker included. */
export declare const SKILL_RETENTION_PER_SKILL_MAX_CHARS = 20000;
/** Total retained-area budget (chars; CC: 25000 tokens). Skills that do not fit whole are skipped
 *  individually — later (smaller) skills may still fit. */
export declare const SKILL_RETENTION_TOTAL_MAX_CHARS = 100000;
/** In-band truncation marker. CC's marker points at `Read` on the skill's file path; sema skills
 *  are spec-supplied content with no filesystem path, so the equivalent recovery route here is
 *  re-invoking the Skill tool (which, post-parity, always serves the FULL text). */
export declare const SKILL_RETENTION_TRUNCATION_MARKER = "[... skill content truncated for compaction; invoke the Skill tool again if you need the full text]";
/** Strip the appended model-supplied `## Input` args section from a Skill tool result body (see
 *  {@link SKILL_INPUT_SECTION_SEPARATOR}); returns the body unchanged when no section is present. */
export declare function stripSkillInputSection(text: string): string;
/**
 * Scan dropped messages for successful Skill tool invocations and merge them over the previous
 * compaction's retained set. Returns the UNBUDGETED merged list, most recent invocation FIRST.
 *
 * - `prevRetained` (the prior compaction's `details.invokedSkills`, newest-first) seeds the set:
 *   every prior entry is older than anything scanned here, and a re-invocation refreshes both the
 *   content and the recency rank (delete-then-set Map insertion order).
 * - Only NON-error Skill results count (an unknown-skill error result carries no skill body).
 * - The skill NAME comes from the paired assistant toolCall's arguments (`skill`, legacy `name`);
 *   the result message alone only knows the tool name.
 */
export declare function extractInvokedSkills(droppedMessages: AgentMessage[], prevRetained: InvokedSkillRetention[] | undefined): InvokedSkillRetention[];
/** Apply the CC-shaped retention budget to a newest-first invoked-skill list: per-skill truncation
 *  (marker-inclusive), then the total budget with SKIP-not-break semantics for over-budget entries.
 *
 *  `maxTotalChars` (window-aware clamp): the CC-shaped 20k/100k caps are UPPER BOUNDS tuned for
 *  ≥100k-token windows, not guarantees — on a small-window model an area that big would push
 *  「summary + retention + kept tail」 past the window on every post-compaction request. A caller
 *  that knows the consuming model's window passes its remaining chars headroom here; the effective
 *  total budget is `min(100k, maxTotalChars)`, and the per-skill cap shrinks to the effective
 *  total so the MOST RECENT skill is truncated-to-fit rather than skipped whole (skip-whole is the
 *  right CC semantics between skills, but under a window clamp it would drop the newest skill in
 *  favor of an older smaller one). A budget too small to hold even the truncation marker retains
 *  nothing. Absent ⇒ the plain CC-shaped budget. */
export declare function budgetInvokedSkillsRetention(newestFirst: InvokedSkillRetention[], maxTotalChars?: number): InvokedSkillRetention[];
/**
 * Replace the bodies of successful Skill tool results with a bounded placeholder before the
 * summarizer sees them. Extraction copies those bodies into the retained invoked-skills area, so
 * leaving the originals in the summarization input would (a) double-charge the window budget and
 * (b) let multi-thousand-char skill texts crowd real conversation out of the summary input clamp.
 * The toolResult MESSAGE stays (shallow-copied, same toolCallId/toolName) so the call/result
 * pairing stays legal for serialization; only its content is swapped for a short note. `groups`
 * lets a split-turn boundary pass both legs at once so the call→name pairing map spans them.
 * `retainedNames` keeps the placeholder honest: a skill the retention budget skipped is disclosed
 * as omitted, not claimed preserved. Non-matching messages pass through by reference.
 */
export declare function replaceInvokedSkillBodiesForSummary(groups: AgentMessage[][], retainedNames: ReadonlySet<string>): AgentMessage[][];
/** Defensive reader for persisted `CompactionDetails.invokedSkills` (details is `unknown` on the
 *  wire; sessions persisted before this field existed simply yield an empty list). */
export declare function readRetainedInvokedSkills(details: unknown): InvokedSkillRetention[];
/** Render the retained invoked-skills area appended to the compaction summary MESSAGE at context
 *  build time (never baked into the persisted summary string — see the module note above). */
export declare function renderInvokedSkillsRetention(skills: InvokedSkillRetention[]): string;
/** Bound on the retained ref list — write-side cap AND the import door's ceiling (import-validate
 *  bounds against the producer's own constant so the two never drift). The list is oldest-first
 *  (carry-forward seed, then this range's refs); over the cap the OLDEST refs are dropped — the
 *  newest elisions are the likeliest to be paged back. */
export declare const PERSISTED_OUTPUT_REFS_MAX_ENTRIES = 50;
/** Collect `<persisted-output ref="…">` handles from tool results in `messages` into `into`
 *  (insertion-ordered Set = first appearance order; duplicates collapse). */
export declare function extractPersistedOutputRefs(messages: AgentMessage[], into: Set<string>): void;
/** Defensive reader for persisted `CompactionDetails.elidedMessages` (RB-398-b①): a non-negative
 *  safe integer, else absent (pre-field sessions / foreign shapes yield undefined ⇒ no wrapper
 *  disclosure — the byte-identical legacy render). */
export declare function readElidedMessages(details: unknown): number | undefined;
/** Defensive reader for persisted `CompactionDetails.unsummarizedMessages` (PTL-shortfall accounting): same contract as
 *  {@link readElidedMessages} — a non-negative safe integer, else absent (pre-field sessions /
 *  foreign shapes ⇒ no uncovered-scale clause, byte-identical wrapper). */
export declare function readUnsummarizedMessages(details: unknown): number | undefined;
/** Defensive reader for persisted `CompactionDetails.activeTools` (RB-402):
 *  the ToolSearch activation snapshot each landed compaction restates. details is
 *  `unknown` on the wire — pre-field sessions and foreign shapes yield an empty list; non-string/
 *  empty members are dropped (the consumer additionally intersects with the current leg's deferred
 *  registry, so an unknown name is inert either way). */
export declare function readCompactionActiveTools(details: unknown): string[];
/** Defensive reader for persisted `CompactionDetails.persistedOutputRefs` (details is `unknown` on
 *  the wire; sessions persisted before this field existed simply yield an empty list). */
export declare function readPersistedOutputRefs(details: unknown): string[];
/** Render the retained handles as a summary footer section — the deterministic counterpart of the
 *  `clearStaleToolResults` marker's "full text persisted; call ReadToolResult with ref …" note.
 *  Empty list ⇒ empty string (pre-existing summaries stay byte-identical). */
export declare function formatPersistedOutputRefs(refs: string[]): string;
/**
 * Compute the file lists from accumulated operations: the display lists stay SORTED (stable
 * summary-tag output), `modifiedFilesByRecency` carries the same modified set most-recent-FIRST
 * for consumers that pick a top-N (working-file attachments).
 */
export declare function computeFileLists(fileOps: FileOperations): {
    readFiles: string[];
    modifiedFiles: string[];
    modifiedFilesByRecency: string[];
};
/** Format file lists as summary metadata tags (each list capped at {@link FILE_LIST_MAX_ENTRIES}). */
export declare function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string;
/**
 * Inverse of {@link formatFileOperations}: strip a TRAILING file-ops footer block from a stored summary.
 * Every summary persisted by `compact()` ends with this footer; when a prior summary is threaded verbatim
 * as the history of a later split-turn compaction (bug-hunt #1), the canonical superset footer is
 * re-appended — so the stale embedded one must be removed first to avoid a duplicate. Anchored at end-of-
 * string, so a `<read-files>`/`<modified-files>` string that legitimately appears mid-body is untouched.
 */
export declare function stripFileOperationsFooter(summary: string): string;
/** Serialize LLM messages to plain text for summarization prompts. */
export declare function serializeConversation(messages: Message[]): string;
