import type { TSchema } from "typebox";
import type { AgentTool } from "../internal/harness-types.js";
import type { ProtocolId } from "../core/protocol-table.js";
/** The protocol slice comes from the protocol table — adding a protocol extends ProtocolId and this
 *  union follows automatically (the origin projection is table-driven, prepare-task). */
export type ToolOrigin = "core" | "caller" | "synthetic" | ProtocolId;
export interface ToolContractDescriptor {
    /** Stable contract identity, e.g. `core.read@2`. Versioned independently of the wire name. */
    contractId: string;
    /** Declared behavior revision (protocol §7.1: declarative — hashing a JS closure proves nothing). */
    implementationRevision: string;
    wireName: string;
    /** Live deployment aliases (ToolSpec.aliases) — dispatchable alternate wire names. Retired-name
     *  replay aliases are gone (RB-476-A, 5.0.0): a persisted old name misses loudly instead. */
    aliases?: string[];
    origin: ToolOrigin;
    /** Structure-only schema digest (descriptions/titles/examples stripped) — presentation-invariant. */
    shapeDigest: string;
    /** Full materialized schema digest (incl. descriptions) — the model-visible wire face. */
    wireSchemaDigest: string;
    /** The presentation card in effect. v1: `builtin:<wireName>` (the factory's inline text). */
    cardId: string;
}
/**
 * Manifest v2 row (protocol §5.4) — {@link projectToolManifest}'s per-tool projection of
 * {@link ToolContractDescriptor} onto the wire-visible manifest plane. REF-D25 (2026-08):
 * this is an intentional projection, not a subset alias — it drops `origin` and normalizes
 * `aliases` from optional to required (empty array when there are none), so it cannot be
 * expressed as `Pick<ToolContractDescriptor, ...>`. `core/trace.ts` (TraceEvent's
 * `prompt.assembled` manifest) and `core/runner/prepare-task.ts` (`Prepared.promptManifest.tools`)
 * both reference this same type — the value flows prepare-task.ts → runtask.ts → trace.ts
 * untouched, so a shape drift between those two sites would make a real call-shape change
 * invisible to replay/audit (the same shapeDigest-collision class documented above on
 * `stripPresentation`).
 */
export interface ToolManifestRow {
    wireName: string;
    aliases: string[];
    contractId: string;
    implementationRevision: string;
    cardId: string;
    shapeDigest: string;
    wireSchemaDigest: string;
}
export declare function computeShapeDigest(schema: TSchema | undefined): string;
export declare function computeWireSchemaDigest(schema: TSchema | undefined, description: string): string;
export interface AttachContractInput {
    contractId: string;
    implementationRevision: string;
    origin: ToolOrigin;
    aliases?: string[];
}
/** Attach a contract descriptor to a materialized tool (factory exit point). Digests are computed
 *  from the tool's REAL mounted schema/description, so they always reflect the wire face. */
export declare function attachToolContract(tool: AgentTool, input: AttachContractInput): void;
/**
 * Resolve a tool's descriptor. Undeclared tools get a deterministic legacy descriptor derived from
 * their shape (`legacy:<shapeDigest>`), origin per the mount channel — an external tool NEVER
 * inherits a core contract by name (§7.2: don't guess contracts from names).
 */
export declare function getToolContract(tool: AgentTool, fallbackOrigin?: ToolOrigin): ToolContractDescriptor;
export declare function hasToolContract(tool: AgentTool): boolean;
/** Manifest projection for the final mounted tool set (manifest v2 `tools`, protocol §5.4). */
export declare function projectToolManifest(tools: readonly AgentTool[], originOf?: (tool: AgentTool) => ToolOrigin): ToolManifestRow[];
/**
 * RB-15: wire-identity collision audit over the FINAL mounted tool set.
 * Rules (plan §6.2 tool row):
 *   - an ALIAS colliding with another tool's canonical name or alias = FATAL (silent misdispatch
 *     of durable replays would follow — never ship such a mount);
 *   - two tools sharing a CANONICAL name = the historic deliberate yield (a caller tool may shadow
 *     a built-in; the harness Map keeps the later mount) — NOT fatal, but returned as an explicit
 *     exemption record so the mount site can surface it (observable, never silent).
 */
export declare function auditToolCollisions(tools: readonly AgentTool[]): {
    yields: Array<{
        name: string;
    }>;
    aliasCollisions: Array<{
        alias: string;
        owners: string[];
    }>;
};
