export type Provider = import("../types").Provider; export type ToolDef = import("../types").ToolDef; /** * The uniform outcome of an evaluation, across every criteria type. * * Tri-state `status` mirrors Anthropic Managed Agents "Outcomes" (`satisfied` / * `needs_revision` / `failed`) — the distinction matters to `refine`: `needs_revision` * is retryable, `failed` is terminal (stop spending). `pass` is derived (`status === * 'satisfied'`) so a boolean consumer never has to special-case the enum. */ export type Verdict = { /** * - Tri-state outcome. */ status: "satisfied" | "needs_revision" | "failed"; /** * - Derived: `status === 'satisfied'`. */ pass: boolean; /** * - 0–10 for the rubric path; null for predicate (pass/fail only). */ score: number | null; /** * - Why it failed / what to improve. '' when satisfied with no notes. */ critique: string; /** * - Concrete fixes (rubric may populate; [] otherwise). */ suggestions: string[]; /** * - Rubric path only: `true` when the grader requested a pinned * `temperature: 0` (its determinism knob) but the model rejected it and the provider silently retried at * the model's DEFAULT (BA-10). Carries the fact the way `recurse` does — the grader ran non-deterministic; * the caller decides what to do. Absent/`false` for predicate (no LLM) and agentic (no pinned temperature). */ temperatureDropped?: boolean | undefined; }; export type EvaluatorOptions = { /** * - LLM provider — REQUIRED for the rubric and agentic paths; predicate needs none. */ provider?: import("../types").Provider | undefined; /** * - Override the adversarial grader system prompt (rubric path). */ prompt?: string | undefined; /** * - Override the adversarial tool-running critic system prompt (agentic path). */ agenticPrompt?: string | undefined; /** * - The critic's SCOPED functional tools (`barebrowse`/`baremobile`) for the * agentic path — what lets it exercise the live artifact rather than read text. Overridable per call via * `EvaluateOptions.tools`. Ignored by predicate/rubric. */ tools?: import("../types").ToolDef[] | undefined; /** * - REQUIRED for the `jev` path — a cheap * calibrated classifier tier (~100-1000x cheaper than a rubric LLM round for classification-shaped verdicts). * Overridable per call via `EvaluateOptions.jevProvider`. Ignored by predicate/rubric/agentic. */ jevProvider?: import("./provider-jev").JevProvider | undefined; }; export type Criteria = { /** * - Deterministic check, no tokens. * MUST return a boolean. A non-boolean return THROWS a `ValidationError` (it is not coerced): a truthy * object/string/number — e.g. a test-runner result returned by mistake — would otherwise launder a * FAILING check into a PASS. Thrown, it routes to `broken-verifier` at recurse's verify slot. */ predicate?: ((result: any) => boolean | Promise) | undefined; /** * - Natural-language grading criteria an LLM scores. Exactly one of predicate|rubric|agentic. */ rubric?: string | undefined; /** * - Instructions for a tool-running critic (D9): how to EXERCISE the live artifact * (open it, click, read console/network) and what would make it fail. Runs an ISOLATED Loop with the scoped * `tools`. The strongest verification — catches what only running the thing reveals. Exactly one of the three. */ agentic?: string | undefined; /** * - * Cheap calibrated classifier door (composes `JevProvider`, the cost tier below `rubric`). `question` is * ONE Jev question object — the SOLE criterion (a classifier takes one instruction, not a layered prompt; * unlike rubric/agentic, `contract` is NOT folded into it here — it is used only as the failed-critique * string). `toVerdict` maps the classifier's per-question answer (`{type:'noul',noul}` / * `{type:'choice',choice,...}` / `{type:'score',score,...}`) to a tri-state status — the caller owns * thresholds/bands (Option A: caller-supplied mapping fn, open + simple, no premature abstraction over * jev's three answer shapes). Requires a `jevProvider` (on the Evaluator or per-call). Exactly one of the four. */ jev?: { question: { type: "noul" | "choice" | "score"; instructions: string; criteria?: any; }; toVerdict: (answer: any) => "satisfied" | "needs_revision" | "failed"; } | undefined; /** * - The shared, authoritative "definition of done" the grader judges against * (A3 / D10). When present it is what success means — not the loose goal. Folded into the rubric/agentic * prompt; for the `jev` door it is used ONLY as the failed-critique string (never folded into `question`). */ contract?: string | undefined; }; export type EvaluateOptions = { /** * - Budget hook. * Judge-call tokens are real spend; forward them to the gate (BA1 lineage) so they count against budget and * are never invisible. For the agentic path EVERY critic round forwards here (re-tagged `kind:'evaluate'`). * A `HaltError` thrown here propagates as a clean governance exit. Wire `wireGate`'s. */ onLlmResult?: ((payload: { usage: any; model: string | null; kind: "evaluate"; }) => any) | undefined; /** * - Per-call override of the agentic critic's scoped tools (else `EvaluatorOptions.tools`). */ tools?: import("../types").ToolDef[] | undefined; /** * - bareguard `policy` forwarded to the agentic critic's Loop — a tool-running * critic MUST be bounded (turn/budget caps come from the gate; the Loop's HARD_ROUND_LIMIT is only a net). */ policy?: Function | undefined; /** * - Per-call override of the `jev` door's classifier * provider (else `EvaluatorOptions.jevProvider`). */ jevProvider?: import("./provider-jev").JevProvider | undefined; }; /** * Output-side judge — the mirror of `Planner` (input-side). Judges whether a result meets a goal, by a * deterministic `predicate`, an LLM `rubric`, a tool-running `agentic` critic, or a cheap calibrated `jev` * classifier tier, returning one uniform `Verdict`. The rubric and agentic paths run an ISOLATED adversarial * critic (separate context + independent system prompt) — that isolation, not a feedback knob, is what * defeats the self-evaluation trap. The agentic path additionally EXERCISES the artifact with scoped tools * (it does not read the diff). The `jev` path composes `JevProvider` (a single classification call, ~100-1000x * cheaper than a rubric round) for classification-shaped verdicts — the caller supplies a `toVerdict` mapping * fn from the classifier's answer to the tri-state status. Composes AROUND a Loop (never inside `loop.js`). * * Built flagged-and-deletable per D11 — opt-in by import; calibrate the rubric/prompt from execution traces. */ export class Evaluator { /** * @param {EvaluatorOptions} [options] * @when you need to judge an output against a goal or contract — deterministically (predicate), by LLM rubric, with a tool-running critic that exercises the live artifact, or by a cheap calibrated classifier (jev) * @fails never throws for a bad grade — returns a Verdict {status: satisfied|needs_revision|failed}; a provider HaltError propagates clean. Judge tokens forward via onLlmResult. * @example * const evaluator = new Evaluator({ provider }); * const verdict = await evaluator.evaluate(goal, result, { rubric }); * if (!verdict.pass) revise(verdict.critique); */ constructor(options?: EvaluatorOptions); provider: import("../types").Provider | null; prompt: string; agenticPrompt: string; tools: import("../types").ToolDef[]; jevProvider: import("./provider-jev").JevProvider | null; /** * Judge `result` against `goal` by exactly one criteria type. * @param {string} goal - The objective the result is judged against. * @param {any} result - The output under judgment. * @param {Criteria} criteria - Exactly one of `predicate` | `rubric` | `agentic` | `jev` (none/more-than-one throws). * @param {EvaluateOptions} [opts] * @returns {Promise} * @throws {ValidationError} not-exactly-one criteria supplied, or rubric/agentic/jev requested with no provider. */ evaluate(goal: string, result: any, criteria: Criteria, opts?: EvaluateOptions): Promise; /** * Agentic path — run an ISOLATED tool-running critic Loop that exercises the artifact, then parse its * final text into a `Verdict`. Isolation is by construction: a brand-new Loop with its own message array * and the harsh `agenticPrompt` system prompt — a separate context window, never the generator's * transcript (A1/D8). Budget visibility: every critic round forwards to `onLlmResult` (re-tagged * `kind:'evaluate'`). A budget HALT during investigation re-throws as a clean `HaltError` (governance * exit) so `refine` stops spending rather than misreading it as a verdict. * @param {string} goal * @param {any} result * @param {string} instructions - The `agentic` criteria string: how to exercise the artifact. * @param {string|null} contract * @param {EvaluateOptions} opts * @returns {Promise} * @throws {ValidationError} no provider, or the critic loop errored / produced no parseable verdict. * @throws {HaltError} a governance cap halted the critic mid-run. */ _evaluateAgentic(goal: string, result: any, instructions: string, contract: string | null, opts: EvaluateOptions): Promise; /** * Jev path — a cheap calibrated classifier verdict tier (the cost tier below `rubric`; ~100-1000x cheaper * for classification-shaped verdicts). Unlike rubric/agentic there is NO layered prompt: `question.instructions` * is the SOLE criterion sent to the classifier (a classifier takes one instruction, not goal+contract+rubric). * `toVerdict` — caller-supplied (Option A: open + simple, no premature abstraction over jev's three answer * shapes) — maps the classifier's answer to a tri-state status; the caller owns thresholds/bands. * @param {any} result * @param {{question: {type: 'noul'|'choice'|'score', instructions: string, criteria?: any}, toVerdict: (answer: any) => any}} jevCriteria * @param {string|null} contract - Used ONLY as the failed-critique string (never folded into the question). * @param {EvaluateOptions} opts * @returns {Promise} * @throws {ValidationError} no jevProvider, `toVerdict` isn't a function, or it returns something other * than a valid tri-state status (BA-15 family — a broken arbiter is named loudly, never coerced; the * error names the TYPE only, never the returned VALUE, F16/BA-1 audit-safety). */ _evaluateJev(result: any, jevCriteria: { question: { type: "noul" | "choice" | "score"; instructions: string; criteria?: any; }; toVerdict: (answer: any) => any; }, contract: string | null, opts: EvaluateOptions): Promise; /** * Defensive JSON parse of a grader response into a `Verdict` (mirrors `Planner._parse`). * @param {string} text * @returns {Verdict} * @throws {ValidationError} when no JSON object can be recovered (a `refine` loop can catch to abort). */ _parse(text: string): Verdict; }