import type { KeyObject } from "node:crypto";
import type { Receipt } from "./attestation.js";
import { type ToolProxyExport } from "./toolproxy.js";
/** Thrown when a caged tool call violates policy (and is blocked). */
export declare class CageDenied extends Error {
readonly tool: string;
constructor(tool: string, message: string);
}
export interface CageOptions {
/** Cryptographic principal the receipt is keyed on — a stable id (SPIFFE id,
* key fingerprint, anything), NOT a mutable display name. */
principal: string;
/** The tools this agent is permitted to call — its capability boundary. A call
* to anything else is denied and recorded. */
allowedTools: string[];
}
export interface ToolOptions {
/** A per-call predicate to deny an in-boundary tool on specific arguments
* (e.g. only allow `pay` below a cap). Returning false → blocked at runtime +
* recorded as a deny. NOTE: the receipt attests the TOOL boundary (tool ∈
* allowedTools); a guard is finer RUNTIME hardening — a guard-denied call to
* an allowed tool is still "in bounds" in the receipt (the tool was permitted).
* Argument-level *proof* (e.g. "amount < cap over all inputs") is the
* bytecode prover's job, not this receipt's. */
guard?: (...args: A) => boolean;
/** Bind the call to its target (a URL, path, counterparty…) — recorded as a
* digest in the receipt, so the receipt is specific to what was acted on. */
subject?: (...args: A) => string;
}
/**
* A runtime cage for an agent's tool calls. Wrap each tool with {@link Cage.tool};
* every call is policy-checked and recorded, and a denied call is BLOCKED. At the
* end {@link Cage.attest} signs an in-bounds receipt verifiable offline by this
* same package.
*/
export declare class Cage {
private readonly opts;
private readonly records;
constructor(opts: CageOptions);
/** Wrap a tool function so each call is caged + recorded. Works for sync and
* async tools (a denied call throws `CageDenied` before the tool runs). */
tool(name: string, fn: (...args: A) => R, options?: ToolOptions): (...args: A) => R;
/** Record a call you invoke yourself (when wrapping the fn isn't convenient). */
record(name: string, allowed: boolean, subject?: string): void;
/** How many calls have been caged so far. */
get callCount(): number;
/** The raw verdict log — the tool-proxy export the verifier consumes. */
toExport(): ToolProxyExport;
/** Sign an in-bounds attestation receipt. Verify it anywhere with
* `verifyReceipt` / the `@coproduct_inc/verify` CLI — no trust in you required. */
attest(privateKey: KeyObject, opts?: {
signedAt?: string;
}): Receipt;
}