/**
 * critic.ts — CRITIC pattern: tool-grounded self-correction loop.
 *
 * Reference: Gou et al., "CRITIC: Large Language Models Can Self-Correct with
 * Tool-Interactive Critiquing", ICLR 2024, arXiv:2305.11738.
 *
 * Design invariant (enforced by the API shape):
 *   Correction is TOOL-GROUNDED only. The verifier MUST produce a structured
 *   discrepancy derived from an external tool call (e.g. run tests, grep,
 *   syntax check, type-check). Pure LLM introspection is explicitly NOT
 *   supported here.
 *
 *   Rationale: Huang et al. (arXiv:2310.01798, "Large Language Models Cannot
 *   Self-Correct Reasoning Yet") demonstrate that models evaluating their own
 *   outputs without external grounding produce net-negative corrections.
 *   Tool-grounded feedback (deterministic oracle, static analyser, test runner)
 *   is the only form of self-correction with reliable empirical gains.
 *
 * Usage example:
 *
 * ```ts
 * import { criticLoop, type CriticVerifier } from "@vauban-org/agent-sdk";
 *
 * // Fake verifier: rejects outputs shorter than 10 chars.
 * const lengthCheck: CriticVerifier<string> = async (output) => {
 *   if (output.length >= 10) return { ok: true };
 *   return { ok: false, discrepancy: `Output too short: ${output.length} chars (min 10)` };
 * };
 *
 * // Fake reviser: pads the string to satisfy the verifier.
 * const padReviser = async (current: string, discrepancy: string): Promise<string> => {
 *   void discrepancy; // use discrepancy to build a targeted revision prompt
 *   return current.padEnd(10, ".");
 * };
 *
 * const result = await criticLoop("hi", lengthCheck, padReviser);
 * // result.output   → "hi........"
 * // result.rounds   → 1
 * // result.verified → true
 * // result.history  → [{ round: 1, discrepancy: "Output too short: 2 chars (min 10)" }]
 * ```
 */
// ─── Core function ────────────────────────────────────────────────────────────
/**
 * Apply a tool-grounded self-correction loop (CRITIC pattern).
 *
 * The loop:
 * 1. Verifies `initial` using the tool-grounded `verify` function.
 * 2. If verification passes → returns immediately (`rounds = 0`).
 * 3. Otherwise → calls `revise(current, discrepancy)` to produce a new
 *    candidate and repeats from step 1, up to `maxRounds` times.
 * 4. Stops when either (a) verification passes or (b) `maxRounds` is reached.
 *
 * Pure module: no side effects, no I/O, no logging.
 * The caller supplies all behaviour via `verify` and `revise`.
 *
 * @param initial   - The initial generated output to verify and potentially revise.
 * @param verify    - Tool-grounded verifier (must call an external tool, not LLM introspection).
 * @param revise    - Produces a revised output given the current output and the discrepancy.
 * @param maxRounds - Maximum number of correction rounds (default: 3).
 *                    Must be a non-negative integer; 0 disables all correction.
 * @returns {@link CriticResult} — final output, number of rounds, verification
 *          status, and the ordered discrepancy history.
 *
 * @throws {TypeError} If `maxRounds` is not a non-negative integer.
 */
export async function criticLoop(initial, verify, revise, maxRounds = 3) {
    if (!Number.isInteger(maxRounds) || maxRounds < 0) {
        throw new TypeError(`criticLoop: maxRounds must be a non-negative integer, got ${String(maxRounds)}`);
    }
    const history = [];
    let current = initial;
    for (let round = 1; round <= maxRounds; round++) {
        const verdict = await verify(current);
        if (verdict.ok) {
            return {
                output: current,
                rounds: round - 1,
                verified: true,
                history,
            };
        }
        // Tool-grounded discrepancy: record and revise.
        history.push({ round, discrepancy: verdict.discrepancy });
        current = await revise(current, verdict.discrepancy);
    }
    // After all revision rounds, run a final verification pass.
    const finalVerdict = await verify(current);
    if (finalVerdict.ok) {
        return {
            output: current,
            rounds: maxRounds,
            verified: true,
            history,
        };
    }
    // maxRounds exhausted without passing — return last output unverified.
    return {
        output: current,
        rounds: maxRounds,
        verified: false,
        history,
    };
}
//# sourceMappingURL=critic.js.map