import { type TracerHook } from "../trace.js";
import type { MaybeCompactOptions } from "../auto-compaction.js";
import type { StaleToolResultOffloadOptions, TaskSpec } from "../types.js";
import type { Context } from "../../internal/llm.js";
import { type ToolResultStore } from "../tool-result-store.js";
import type { Prepared, RunnerDepsSeat } from "./contracts.js";
import { type ContextWindowOverlay } from "../context-settings.js";
import { type CompactionSettings } from "../../internal/harness.js";
/**
 * The maybeCompact call arguments that MUST be assembled identically on all three
 * of runtask's compaction lanes (turn boundary / prompt-too-long recovery / end-of-task).
 *
 * Those lanes carried three hand-copied assemblies whose own comments said "must not silently
 * diverge" — a discipline enforced only by human diffing. This module makes the identity structural.
 * It is deliberately NARROW: only the parts that are the same invariant live here. Everything else
 * the three call sites pass (model source, brain, minTokens, force, trigger, window safety, and the
 * end-of-task lane's deliberate ABSENCE of `signal`) is a legitimate per-lane difference and stays at
 * the call site, where its reason is written down.
 *
 * Every export is a free function: the turn-boundary lane assembles its call inside `createTurnBoundary`
 * (a module-level function with no `this`), so a method would not be reachable from all three sites.
 * Nothing here WRITES runner state; one export ({@link legContextOverlayOption}) READS the live deps seat,
 * because reading it at the moment of the pass — not at prepare — is the whole of what it states.
 */
/**
 * Opt-in working-file attachments (LONGRUN-2 / CC 198 post-compact restore parity).
 *
 * CC parity: post-compact file re-read is DEFAULT ON (CC hard-codes it;
 * LONGRUN-2 measured ≈2.3 extra read round-trips per compaction without it). `false` opts out; an
 * object customizes caps. Selection set = most recently READ (CC readFileState semantics) with a
 * modified-files fallback inside maybeCompact. Returns `undefined` when attachments are off or the
 * task has no hands (no `readTaskFile` ⇒ nothing can be re-read).
 */
export declare function buildWorkingFileAttachments(spec: TaskSpec, prepared: Prepared): MaybeCompactOptions["workingFileAttachments"];
/**
 * `MaybeCompactOptions.contextInstructionFiles`: the deployment's instruction-file content (the CLAUDE.md
 * family) delivered to the SUMMARIZER, assembled once here and spread on all three lanes — the compaction
 * boundary is where the summary REPLACES the transcript that carried those instructions.
 *
 * Contract:
 *  - Bytes = `Prepared.projectInstructionContent`, the RAW loader text captured under the same non-blank
 *    predicate that composes the project layer. Not the assembled `memoryBlock` (model-authored in-band
 *    bytes would gain an instructing envelope), not the COMPOSED project block (`contextInstructionFilesSection`
 *    neutralizes the whole authority family, `user_memory`/`scope` included), not `instructionSources`
 *    (path + hash only). Raw text in, one fence at the mint.
 *  - Provenance: REPOSITORY-CONTROLLED text delivered through a host callback — delivery is not authorship;
 *    the mint's neutralization stops tag breakout, not a sentence asking for an omission. Two no-code exits
 *    for a deployment that does not want it: do not wire the loader, or return vouched content. A separate
 *    deployment-vouched summarization-instructions seat is an open design candidate, not built here.
 *  - Both summary forms, no per-form split: fork eligibility is decided per pass inside maybeCompact, and the
 *    form NOT covered by a `compModel`-gated split is exactly the fork that degrades mid-pass to the
 *    independent form; the section rides the APPENDED instruction message, never the cached prefix.
 *  - No new size knob: the bound is `fitContextInstructionFilesSection` (independent form only). Its three
 *    known limits are accepted knowingly: a token-dense payload can pass a chars-domain fit and still overflow;
 *    an unknown `contextWindow` leaves the section unbounded; the FORK form cannot fit and degrades ONCE. When
 *    a limit bites the boundary FAILS (the section is a fixed request part the retry loop cannot drop) — the
 *    task loses that compaction rather than sending a shorter one; making the section participate in the
 *    retry loop is a library-face contract change, tracked there.
 *  - Cost: instruction-file content + exactly 716 chars of framing on every summarization request, both
 *    forms, once per pass (pinned in the REF-A2 suite). Deployments that never wired the loader pay nothing:
 *    the key is ABSENT, so their requests are byte-identical to the pre-wiring shape.
 */
export declare function contextInstructionFilesOption(prepared: Prepared): Partial<Pick<MaybeCompactOptions, "contextInstructionFiles">>;
/**
 * The CC-form fork seam, assembled identically on all three lanes (REF-A2): the
 * summary request forks the main lane's latest real request (recorded by prepare-task's provider
 * shim) instead of re-serializing the conversation into an independent full-price request.
 * `maybeCompact` consults the accessor per pass and only when the summary model IS the main model;
 * before the run's first main-loop call the accessor returns `undefined` and the independent form
 * runs unchanged.
 *
 * Lossy-projection guard (SEMA-ONLY — CC has no request-layer reducers): the recorded request is a
 * PROJECTION of the session, and when ANY default reducer made it lossy (guard-trim message drops,
 * clearStale content blanking, the aggregate tool-result/media caps, the orphan sweep), that
 * projection is missing history the summary would PERMANENTLY replace — measured live: a fork of a
 * trimmed request loses the fact-survival suite's fact; a fork of a clearStale'd request summarizes
 * `[tool result cleared …]` markers. That guard lives at the RECORDING side
 * (prepare-task arms `requestLossyRef` per request build; a lossy request records `undefined`), so
 * every lane degrades to the independent form — which reads the FULL session — automatically.
 *
 * `disable` — the PTL-recovery lane's structural off-switch: the provider just rejected the very
 * prefix a fork would resend, so a fork attempt there is a guaranteed wasted round-trip before the
 * internal fallback. The other lanes pass `false`.
 */
export declare function forkContextOption(prepared: Prepared, disable: boolean): Pick<MaybeCompactOptions, "forkContext">;
/**
 * Compaction-boundary center-candidate adoption. Absent (an empty object, NOT a
 * `centerAdoption: undefined` key) = restate as before; a boundary re-pin hashes the same artifact
 * identity on every lane.
 */
export declare function centerAdoptionOption(prepared: Prepared): Partial<Pick<MaybeCompactOptions, "centerAdoption">>;
/** Defaults (object-present, field-absent). Named per the magic-number rule. */
export declare const STALE_OFFLOAD_DEFAULT_KEEP_RECENT_PER_TOOL = 3;
export declare const STALE_OFFLOAD_DEFAULT_MIN_SAVINGS_CHARS = 2000;
/** Resolved (validated, defaulted) knob — see {@link resolveStaleToolResultOffload}. */
export interface ResolvedStaleToolResultOffload {
    keepRecentPerTool: number;
    minSavingsChars: number;
}
/**
 * Validate + default the spec knob. Fail-loud on non-finite/negative/fractional
 * values (a computed NaN silently re-defaulting is the ||0-fold this repo's engineering code bans);
 * `undefined` knob ⇒ `undefined` (feature completely off).
 */
export declare function resolveStaleToolResultOffload(knob: StaleToolResultOffloadOptions | undefined): ResolvedStaleToolResultOffload | undefined;
/** The pointer that replaces a stale result's text in the request projection. PURE function of
 *  (toolName, ref, chars) — that determinism is the DECISION-stability guarantee: a result already
 *  replaced maps to the same pointer bytes on every later request (no flip-flop, no re-decision
 *  churn). It is NOT full prefix stability: the verbatim→pointer TRANSITION itself (a result
 *  crossing the staleness line as newer same-tool results arrive) rewrites that message's bytes
 *  once, invalidating the provider cache from that position for one request — a bounded,
 *  once-per-result break the `minSavingsChars` floor is there to amortize.
 *  Deliberately NOT `offloadPagebackHint` (the preview's hint): that hint's wording is a
 *  function of the LIVE reachable-tool set, and this pointer is re-derived per request — a mid-run
 *  ToolSearch activation would flip its bytes and break the very prefix stability this file pins.
 *  The reader is named by its real mounted name (`read_tool_result` is a
 *  retired alias — a model following it burned a rejected call first). */
export declare function buildStaleOffloadPointer(toolName: string, ref: string, chars: number): string;
/**
 * The request-side projection: replace STALE same-tool results with byte-stable
 * pointers. "Stale" = has ≥ `keepRecentPerTool` NEWER results of the same tool name in this request
 * — a monotone predicate (a result never gains "recency" back), so a replacement decision made on
 * one request holds on every later one and re-derivation is deterministic: no run-scoped mutable
 * decision state is needed for byte stability, only the pointer's purity (see
 * {@link buildStaleOffloadPointer}) and the store's write-once `put`.
 *
 * The session transcript is NEVER touched — this runs on the outgoing {@link Context} only.
 * Error results, image/document-bearing blocks' non-text parts, already-offloaded previews, and
 * replacements that would save < `minSavingsChars` are left verbatim. The full text is persisted
 * under a deterministic content-digested ref (`buildToolResultRef(sessionId, toolCallId,
 * toolResultContentSegment(text))` — a `~`-separated three-segment mint whose digest is its OWN
 * segment; write-once, so re-projection on every turn re-puts a no-op; the digest exists because
 * tool-call ids carry no cross-turn uniqueness contract), readable back via `read_tool_result`.
 */
export declare function projectStaleToolResults(context: Context, cfg: ResolvedStaleToolResultOffload, store: ToolResultStore, sessionId: string, 
/** Run-scoped cache of refs already persisted by THIS run: without it the
 *  write-once `put` is still re-issued every request — on the file backend that is a
 *  write-then-discard round-trip per stale result per turn. Caller owns the Set's lifetime. */
writtenRefs: Set<string>): Promise<Context>;
/**
 * MF-18 修② — fidelity disclosure: the summary INPUT was clipped to the compaction model's
 * window. Fires pre-call, so the disclosure survives a failed attempt. All three lanes emit the SAME
 * frame; the end-of-task lane passes `spec.tracer ?? deps.tracer` / `spec.taskId ?? sessionId`
 * explicitly because `RunState.telemetry` (which holds exactly those two resolved values) is not in
 * scope inside `finish()`.
 */
export declare function emitInputTruncated(tracer: TracerHook | undefined, taskId: string): NonNullable<MaybeCompactOptions["onInputTruncated"]>;
/**
 * The deployment's per-model window overlay in force for THIS pass — the one option of the three lanes that
 * is deliberately a LIVE read rather than a prepared value.
 *
 * Two reads, both at the moment of the pass: the leg's own catalog word (the harness's current ref, so a
 * mid-task degrade moves the key along with the model) and the Runner's current deps seat (so a `swapDeps`
 * reaches a leg already running). An object-pinned leg has no word and therefore no overlay — the key is
 * simply absent, which `maybeCompact` reads as "the model card's own declarations", the pre-seat behavior.
 */
export declare function legContextOverlayOption(prepared: Prepared, runner: RunnerDepsSeat): Pick<MaybeCompactOptions, "contextOverlay">;
/**
 * The compaction SETTINGS a pass runs under — the assembly all three lanes share.
 *
 * `{ ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction }` was hand-copied at each lane, and it is where the
 * deployment's live `enabled` declaration belongs: `maybeCompact` has exactly one enablement gate (it reads
 * `settings.enabled`), so folding the overlay in HERE makes the deployment's switch reach the boundary pass,
 * the recovery pass and the end-of-task summary by one edit instead of three, and keeps "who decides whether
 * compaction runs" a single expression ({@link compactionEnabled}: the request authored it > the deployment
 * declared it > on).
 */
export declare function legCompactionSettings(spec: TaskSpec, overlay: ContextWindowOverlay | undefined): CompactionSettings;
