/**
 * `TranscriptModel` — a visitor over a build-conversation transcript.
 *
 * Smithy's agent-building session is, underneath, an ordinary model conversation:
 * an ordered list of {@link Turn}s, each a bag of typed {@link Block}s. Before any
 * of that can be shown to a person — or written to a session log — it has to be
 * *cleaned* and *projected*: secrets stripped, runaway whitespace collapsed, giant
 * blobs (a pasted file, a base64 image) redacted to a short placeholder, and the
 * whole thing reshaped from the gateway's wire vocabulary into a small, flat,
 * render-friendly form. The original sanitizers did this as a scatter of
 * `normalize*` helpers; this module folds them into a single disciplined visitor.
 *
 * The visitor is *table-driven*. {@link TranscriptModel} holds one
 * {@link BlockVisitor} per block kind; walking a turn is a `switch`-free dispatch
 * through that table, so adding a new block kind is adding one table entry, never
 * editing a ladder. Each visitor is a pure function `(block, ctx) => RenderBlock |
 * null`; returning `null` drops the block (e.g. an empty text fragment that
 * collapsed to nothing). The sanitizers themselves are likewise pure string
 * transforms composed in a fixed order, so the projection is deterministic and
 * trivially testable.
 *
 * `accept(turns)` is the one public entry point: it walks every turn, runs each
 * block through its visitor, and returns a {@link RenderTranscript}. Nothing here
 * touches a terminal — rendering lives behind the {@link ForgeView} text seam.
 */
import type { Block, CommandBlock, ImageBlock, TextBlock, ThinkingBlock, ToolCallBlock, ToolResultBlock, Turn } from "../../llmgateway/contract";
/** The kind of every block in a projected transcript (mirrors {@link Block}). */
export type RenderBlockKind = "text" | "thinking" | "tool_call" | "tool_result" | "image" | "command";
/** A speaker label, derived from a {@link Turn}'s role. */
export type RenderRole = "user" | "assistant" | "tool";
/**
 * One sanitized, flattened content fragment ready to render.
 *
 * Every block kind collapses to this single shape: a `kind` tag, a one-line
 * `label` naming the fragment for a viewer, and the cleaned `text` to show. The
 * optional `redacted` flag marks fragments whose body was replaced by a
 * placeholder (a long blob, binary media, a secret), so a renderer can style
 * them differently.
 */
export interface RenderBlock {
    /** Which block kind this projection came from. */
    readonly kind: RenderBlockKind;
    /** A short, human-readable label (e.g. `tool · read_file`). */
    readonly label: string;
    /** The sanitized, render-ready body text. */
    readonly text: string;
    /** True when {@link text} is a placeholder standing in for omitted content. */
    readonly redacted?: boolean;
}
/** A single projected turn: a speaker plus its surviving render blocks. */
export interface RenderTurn {
    /** The speaker, projected from the source turn's role. */
    readonly role: RenderRole;
    /** The sanitized blocks, in source order, with dropped blocks removed. */
    readonly blocks: readonly RenderBlock[];
}
/** The full result of {@link TranscriptModel.accept}: a render-ready transcript. */
export interface RenderTranscript {
    /** Every projected turn, in source order. */
    readonly turns: readonly RenderTurn[];
    /** Count of fragments whose body was redacted across the whole transcript. */
    readonly redactionCount: number;
}
/**
 * Tunable thresholds for the sanitizing passes.
 *
 * Defaults are deliberately conservative: collapse whitespace always, redact any
 * single fragment longer than {@link maxLength} characters, and replace anything
 * that matches a secret pattern. A caller can widen or tighten these per session.
 */
export interface SanitizeOptions {
    /** Bodies longer than this (in characters) are redacted to a placeholder. */
    readonly maxLength: number;
    /** Extra regexes whose matches are masked, on top of the built-in set. */
    readonly secretPatterns: readonly RegExp[];
}
/** The default sanitizing thresholds used when a caller passes none. */
export declare const DEFAULT_SANITIZE_OPTIONS: SanitizeOptions;
/** The per-block context a visitor receives alongside the block it projects. */
export interface VisitContext {
    /** The sanitizing thresholds in force for this walk. */
    readonly options: SanitizeOptions;
    /** The role of the turn the block belongs to. */
    readonly role: RenderRole;
}
/**
 * A visitor for one block kind: a pure projection from a typed block to a
 * {@link RenderBlock}, or `null` to drop the block from the output.
 */
export type BlockVisitor<B extends Block> = (block: B, ctx: VisitContext) => RenderBlock | null;
/** The complete dispatch table: one visitor keyed by each {@link Block} kind. */
export interface VisitorTable {
    readonly text: BlockVisitor<TextBlock>;
    readonly thinking: BlockVisitor<ThinkingBlock>;
    readonly tool_call: BlockVisitor<ToolCallBlock>;
    readonly tool_result: BlockVisitor<ToolResultBlock>;
    readonly image: BlockVisitor<ImageBlock>;
    readonly command: BlockVisitor<CommandBlock>;
}
/**
 * The default visitor table — the projection rules the original `normalize*`
 * helpers encoded, gathered into one place.
 *
 * Each entry sanitizes the block's salient text, attaches a descriptive label,
 * and returns a {@link RenderBlock}. Text fragments that collapse to nothing are
 * dropped (`null`); images never carry their bytes into the projection (the
 * base64 payload is always redacted to a one-line descriptor).
 */
export declare const DEFAULT_VISITORS: VisitorTable;
/**
 * A visitor over a build-conversation transcript.
 *
 * Construct one with optional sanitize {@link SanitizeOptions} and an optional
 * override {@link VisitorTable}, then call {@link accept} with a turn list to get
 * back a sanitized, render-ready {@link RenderTranscript}. The model is stateless
 * between calls — every `accept` is independent — so a single instance can be
 * reused across as many transcripts as a session produces.
 */
export declare class TranscriptModel {
    private readonly options;
    private readonly visitors;
    constructor(options?: Partial<SanitizeOptions>, visitors?: Partial<VisitorTable>);
    /**
     * Walk `turns`, sanitize and project every block, and return the result.
     *
     * Turns are visited in order; within each turn, blocks are dispatched through
     * the visitor table by kind. A visitor returning `null` drops its block. A turn
     * is kept even when all its blocks drop (an empty {@link RenderTurn}) so the
     * speaker sequence is preserved for the renderer.
     */
    accept(turns: readonly Turn[]): RenderTranscript;
    /**
     * Dispatch one block to its visitor.
     *
     * The `block.kind` tag narrows the union, and the matching table entry — typed
     * to that exact variant — does the projection. There is no `switch`: the table
     * *is* the dispatch.
     */
    private visit;
}
/**
 * The minimal text seam Smithy renders through.
 *
 * Deliberately tiny — two methods — and free of any terminal toolkit, so the
 * builder loop can `show` lines of a projected transcript and `ask` the user for
 * their next instruction without ever importing Ink or coupling to a UI. A richer
 * view (a TUI, a web pane) is slotted in later by implementing this interface.
 */
export interface ForgeView {
    /** Present one already-formatted line to the user. */
    show(line: string): void;
    /** Prompt the user with `question` and resolve their typed answer. */
    ask(question: string): Promise<string>;
}
/**
 * The default {@link ForgeView}: stdout for output, a readline prompt for input.
 *
 * It writes each shown line straight to the output stream (a trailing newline is
 * added) and reads a single line of input per `ask` via Node's `readline`. The
 * readline interface is created lazily on the first `ask` and closed by
 * {@link close}, so a view that only ever `show`s never opens an input handle.
 */
export declare class ConsoleForgeView implements ForgeView {
    private readonly output;
    private readonly input;
    private rl;
    constructor(output?: NodeJS.WritableStream, input?: NodeJS.ReadableStream);
    show(line: string): void;
    ask(question: string): Promise<string>;
    /** Close the underlying readline interface, if one was ever opened. */
    close(): void;
    /** Open the readline interface on first use; reuse it thereafter. */
    private ensureReadline;
}
/**
 * Format a {@link RenderTranscript} as flat lines for a {@link ForgeView}.
 *
 * A small convenience so a caller can pipe a projected transcript straight to
 * `view.show`. Each block becomes a labelled line (or block of lines for
 * multi-line bodies); turns are separated by a blank line. This lives next to the
 * model because it is the natural pairing of "project, then show".
 */
export declare function formatTranscript(transcript: RenderTranscript): string[];
