import { type TSchema } from "typebox";
import type { AgentTool } from "../../internal/harness-types.js";
import type { TerminalBlockedDetail } from "../terminal-cause.js";
import { type ResolvedSkillListingBudget } from "../skill-listing-budget.js";
import { type SkillGrantTable } from "../skill-grant.js";
/** Reserved name of the injected structured-output tool (CC 2.1.187 `StructuredOutput`; batch-A rename — old
 *  "submit_output" is canonicalized for pre-rename durable state). */
export declare const OUTPUT_TOOL_NAME = "StructuredOutput";
/** Reserved name of the injected blocked-report signal tool (PascalCase: `report_blocked`→`ReportBlocked`). */
export declare const REPORT_BLOCKED_TOOL_NAME = "ReportBlocked";
/** Name of the injected code-review findings echo tool (CC 2.1.207 parity — 锚 pretty.js:361412 `BCe`). */
export declare const REPORT_FINDINGS_TOOL_NAME = "ReportFindings";
/** Default `submit_output` retries (council OS3); total attempts = retries + 1. Overridable via `TaskSpec.outputRetries`. */
export declare const OUTPUT_DEFAULT_RETRIES = 2;
/**
 * Resolve the per-task cap on *consecutive failed* `submit_output` attempts. The task fails with
 * `output.invalid` when the failure streak EXCEEDS this value, so total attempts = cap + 1
 * (default 2 → 3 attempts; `outputRetries: 0` → cap 0 → fail on the first invalid submit). Illegal
 * values (NaN/Infinity/negative) fall back to the default; fractional values floor down.
 */
export declare function resolveOutputRetries(outputRetries?: number): number;
export interface BlockedRef {
    reason?: string;
    /** Written by the engine when a hook seat kept the prompt back (never by the `ReportBlocked` tool): the terminal's
     *  `detail`. Absent = the model's own report. */
    detail?: TerminalBlockedDetail;
}
/** Captures the validated object a `submit_output` call submitted (structured output, 1.41). `set` is
 *  flipped so we can tell "model submitted {}" from "never called". Mirrors `BlockedRef`. */
export interface OutputRef {
    value?: unknown;
    set?: boolean;
}
/**
 * @param strictSchema CC 2.1.205 parity (strict-output-schema.ts): the STRICT derivation of `schema` when
 *   it converted (`additionalProperties:false` stamped, subset-validated). It becomes the tool's
 *   `parameters` — both the model-visible wire schema (CC sends it as `strictInputJSONSchema`) and the
 *   validation schema (the strict form only TIGHTENS the caller's schema, so anything it accepts is valid
 *   under the original — CC's Ajv-against-original validation agrees on every accepted submission).
 *   Absent (fallback / legacy callers) → the caller's schema is served as-is, the pre-205 behavior.
 */
export declare function createOutputTool(ref: OutputRef, schema: TSchema, strictSchema?: TSchema): AgentTool;
export declare function createReportBlockedTool(ref: BlockedRef): AgentTool;
/** One reported finding (the CC 207 wire shape — see {@link createReportFindingsTool}). */
export interface ReportedFinding {
    file: string;
    line?: number;
    summary: string;
    failure_scenario: string;
    category?: string;
    verdict?: "CONFIRMED" | "PLAUSIBLE";
    outcome?: "fixed" | "skipped" | "no_change_needed";
}
/** Build the injected `ReportFindings` echo tool (CC 2.1.207 parity — description verbatim from 锚
 *  pretty.js:361413; `effect: "read"` mirrors CC `isReadOnly()`/`isConcurrencySafe()` → parallel-safe). */
export declare function createReportFindingsTool(): AgentTool;
/** Reserved name of the injected skill-loading tool (present only when `spec.skills` is non-empty). */
export declare const SKILL_TOOL_NAME = "Skill";
/** Per-skill LOAD gate on `SkillSpec.content` (CC 2.1.207 parity: CC's only invoke-time size door is a 1MB file-load gate — an over-limit skill is REJECTED
 *  WHOLE, never truncated, and the invoked body enters context untruncated). Sema skills are spec-supplied, so the equivalent gate sits at spec assembly:
 *  an oversized skill is excluded from the disclosure block and the tool, with an operator-visible config error. The compaction-time retention caps are a
 *  different door, deliberately. */
export declare const SKILL_CONTENT_MAX_CHARS: number;
/** Total per-invoke cap for a skill's inlined attachments (`SkillSpec.files`) — an ATTACHMENT-face budget, distinct from the (gone) body truncation door:
 *  the body is delivered untruncated at invoke time (CC parity), while attachments ride along bounded and truncation-disclosed. */
export declare const SKILL_ATTACHMENTS_MAX_CHARS = 50000;
/** Per-attachment cap on the PATH rendered in its `###` header — one pathological path must not eat the budget. Overflow truncates with an ellipsis. */
export declare const SKILL_ATTACHMENT_PATH_MAX_CHARS = 512;
interface SkillLike {
    name: string;
    description: string;
    content: string;
    /** The skill's two lists (`SkillSpec.allowedTools` / `disallowedTools`) — carried so a successful activation writes its rows into the run's grant table. */
    allowedTools?: string[];
    disallowedTools?: string[];
    /** Optional attachments (SkillSpec.files): paths in the block, delivered inline on invoke under {@link SKILL_ATTACHMENTS_MAX_CHARS}. Same caller-trusted
     *  contract as `content` — core never writes them to disk (deployment's half). */
    files?: Array<{
        path: string;
        content: string;
    }>;
    /** Optional base directory (SkillSpec.baseDir) — see `@contract skill.base_dir`. Absent ⇒ byte-identical result. */ baseDir?: string;
}
/** [c209-C] The metadata slice of a skill the LISTING faces consume (disclosure block + the
 *  skills_listing turn attachment): name, description, attachment paths — never the body. The
 *  Prepared seam projects `SkillSpec`s down to this shape so the run loop's announce lane holds no
 *  skill content. `SkillLike` is structurally assignable (its `files` entries simply carry an extra
 *  `content` the listing renderers never read). */
export interface SkillListingEntry {
    name: string;
    description: string;
    files?: Array<{
        path: string;
    }>;
    /** The skill's rank in the DEPLOYMENT'S DECLARATION order (`TaskSpec.skills`, first-wins
     *  dedupe applied, 0 = declared first). Lower = higher priority. Used ONLY to decide which skills keep
     *  their descriptions when the block overflows its byte budget ({@link buildSkillsBlock} tier B); the
     *  DISPLAY order stays name-sorted, so adding this never moves a line.
     *
     *  Why declaration order: CC 220's `sbs` (@317547) takes a priority function and is called with
     *  `uNt(name)` (@608552 → @402383) = usage count decayed by recency of last use, and additionally
     *  pins every `bundled` skill's description unconditionally. Core has NEITHER axis — no cross-session
     *  skill-usage store, and no bundled/user distinction (every skill arrives through the same
     *  caller-supplied `TaskSpec.skills`). Declaration order is the one priority statement the deployment
     *  can actually make here, and it is the same statement 220's bundled-pin encodes ("these matter most,
     *  keep their descriptions"). Absent ⇒ the entry's array index is used, i.e. the prior behavior. */
    declaredRank?: number;
}
/** Dedupe by name (first occurrence wins) and sort by name — one deterministic list shared by the disclosure block
 *  and the tool, so what the prompt promises is exactly what the tool serves. Each field is READ ONCE, BY NAME, and
 *  both consumers see the copy: the gate screens this list while the invoke substitutes from it, so a `get baseDir()`
 *  answering those two reads differently passed a screen that measured a value the model never received — and a rest
 *  copy would silently drop an INHERITED or non-enumerable list, i.e. lose a skill's grant or its refusals. */
export declare function normalizeSkills(skills: SkillLike[] | undefined): SkillLike[];
/** [c209-C] The skills listing's lead line — single-sourced so the run loop's durable-resume
 *  transcript probe (MED-3② skills arm, runtask) matches EXACTLY what the initial frame carries
 *  (probing the bare `<skills>` fence would be more collision-prone in model-quoted text). */
export declare const SKILLS_LISTING_PROBE_HEADER = "The following skills are available for this task.";
/** [c209-C] One skill's disclosure line — `- name: description[(files 尾缀)]` with the per-skill
 *  description cap. Single-sourced so the skills_listing DELTA frame (turn-attachments) renders adds
 *  with byte-identical line shape to the initial `<skills>` block. */
export declare function skillListingLine(s: SkillListingEntry, descMaxChars?: number): string;
/** What one {@link renderSkillsBlock} call produced: the block, and which skills the budget degraded. */
export interface SkillsBlockRender {
    /** The rendered block — what {@link buildSkillsBlock} returns. */
    text: string;
    /** Skills listed WITHOUT their description (tier B's unspent candidates, or every listed name under
     *  tier C), in display order. Raw names: this is host-facing structured data, not prompt text. */
    nameOnly: readonly string[];
    /** Skills the block could not list at all (tier C's overflow tail). The `Skill` tool still serves them. */
    dropped: readonly string[];
}
/** The text-only face of {@link renderSkillsBlock} — the `<skills>` BLOCK's face, not the listing
 *  family's: the drift frame renders its own arms through the shared tier engine
 *  ({@link renderSkillLinesWithin}), which is where "one ruler for every frame" lives. */
export declare function buildSkillsBlock(skills: ReadonlyArray<SkillListingEntry>, budget?: ResolvedSkillListingBudget): string | undefined;
/** Render the `<skills>` disclosure block (metadata only — bodies stay behind the tool).
 *  [c209-C] REVERSAL: no longer composed into the stable system prompt — this is now the RENDERER for
 *  the `skills_listing` initial frame (first-user-turn reminder / boundary re-announce), so the
 *  cached prefix carries zero skill bytes (design/C §2.3; CC 209 classic ships the same listing as a
 *  first-turn reminder). `budget` absent ⇒ the seat reader's no-knob answer ({@link SKILL_LISTING_DEFAULT_BUDGET}).
 *
 *  The fence and its four header lines are this lane's frame; the budget arithmetic and the three
 *  degradation tiers belong to {@link renderSkillLinesWithin}, which the drift frame renders through
 *  as well. {@link buildSkillsBlock} is the text-only face; this one additionally reports what the
 *  budget cost, for the disclosure lane. */
export declare function renderSkillsBlock(skills: ReadonlyArray<SkillListingEntry>, budget?: ResolvedSkillListingBudget): SkillsBlockRender | undefined;
/**
 * The skills VOCABULARY of the one folding engine (`listing-fold.ts` `foldListingWithin`): the full
 * `- name: description` line, the name-only line, the block's cap marker and its overflow count line,
 * measured byte-exact inside a caller-supplied FRAME — the engine both {@link renderSkillsBlock} and
 * the drift frame's ADD arm render through, so the initial `<skills>` block and a later "new skills are
 * now available" announcement degrade by the same rules against the same number — the number the seat
 * reader resolved (`@contract skills.listing_budget_enforced_as_declared`), which is the frame's whole
 * bound: the listing is an intact-class attachment, so no delivery lane measures it a second time.
 *
 * Tier B follows CC 220 `sbs` @317547-317586 (reserve the marker + every name-only line, then spend
 * the slack on descriptions in {@link SkillListingEntry.declaredRank} order); tier C closes with an
 * honest `(… +N more skills …)` count line — the tool still serves all of them.
 */
export declare function renderSkillLinesWithin(skills: ReadonlyArray<SkillListingEntry>, opts: {
    /** The whole frame's byte budget — honoured as given; the seat reader is the one place that decides it. */
    blockMaxBytes: number;
    descMaxChars: number;
    frame: (lines: readonly string[]) => string;
}): SkillsBlockRender | undefined;
/**
 * The injected `skill` tool: returns a skill's full body as a tool result.
 *
 * A SUCCESSFUL activation writes the skill's two lists into the run's grant table (`grants`, origin `model`): its
 * `allowed-tools` then run without asking and its `disallowed-tools` are refused for the rest of the run; an unknown skill
 * throws first and writes nothing. Activating a skill that declares a list was itself a question (the gate reads this
 * tool's seat off the call's arguments — `Execute skill: <name>`), so a write here always follows a statement. The tool
 * runs ALONE in its batch: a call after it in the same message is judged after the rows exist.
 */
export declare function createSkillTool(skills: SkillLike[], grants?: SkillGrantTable): AgentTool;
export {};
