export type Verdict = import("./evaluator").Verdict; export type RefineOptions = { /** * Build one generation. On iteration 0, `lastResult`/`critique` are null and `history` is empty. Fresh-feedback * (D6/A1) is the consumer's to realize here: seed a NEW Loop with `{goal + critique}` rather than continuing the * failed transcript — anchoring on a wrong answer defeats the independent verifier. `history` is a fresh * shallow COPY of every prior `{result, verdict}` in order (a SkillOpt rejected-attempt buffer, BA-14): a * consumer MAY surface the failed attempts verbatim ("you already wrote these, they failed X — write something * different"), the lever that recovers a temperature-fixed model's fixation rut where escalation is inert * (`poc/ba14-rejected-buffer.mjs`: flat-temp 50%→100%). *Structurally* mutating the copy (push/splice/reorder) * is safe; the `{result, verdict}` entries are SHARED references into refine's internal history (and the returned * `outcome.history`), so treat them as READ-ONLY — deep-mutating an entry corrupts the outcome. */ attempt: (args: { iteration: number; lastResult: any; critique: string | null; contract: string | null; history: Array<{ result: any; verdict: Verdict; }>; }) => any; /** * Judge a result — typically `evaluator.evaluate(goal, result, { rubric, contract })`. */ evaluate: (result: any, ctx: { iteration: number; contract: string | null; }) => (Verdict | Promise); /** * - The shared definition of done (A3/D10), forwarded to BOTH `attempt` and * `evaluate` so generator and critic agree on what success means. */ contract?: string | undefined; /** * - Hard cap. The REAL bound is bareguard maxTurns / budget. */ maxIterations?: number | undefined; /** * - Stop on the first satisfied verdict. */ stopOnPass?: boolean | undefined; }; export type RefineOutcome = { /** * - The last (best available) result. */ result: any; /** * - Its verdict. */ verdict: Verdict | null; /** * - How many attempts ran. */ iterations: number; /** * - Every attempt + verdict, in order. */ history: Array<{ result: any; verdict: Verdict; }>; }; /** @typedef {import('./evaluator').Verdict} Verdict */ /** * @typedef {object} RefineOptions * @property {(args: {iteration: number, lastResult: any, critique: string|null, contract: string|null, history: Array<{result: any, verdict: Verdict}>}) => any} attempt * Build one generation. On iteration 0, `lastResult`/`critique` are null and `history` is empty. Fresh-feedback * (D6/A1) is the consumer's to realize here: seed a NEW Loop with `{goal + critique}` rather than continuing the * failed transcript — anchoring on a wrong answer defeats the independent verifier. `history` is a fresh * shallow COPY of every prior `{result, verdict}` in order (a SkillOpt rejected-attempt buffer, BA-14): a * consumer MAY surface the failed attempts verbatim ("you already wrote these, they failed X — write something * different"), the lever that recovers a temperature-fixed model's fixation rut where escalation is inert * (`poc/ba14-rejected-buffer.mjs`: flat-temp 50%→100%). *Structurally* mutating the copy (push/splice/reorder) * is safe; the `{result, verdict}` entries are SHARED references into refine's internal history (and the returned * `outcome.history`), so treat them as READ-ONLY — deep-mutating an entry corrupts the outcome. * @property {(result: any, ctx: {iteration: number, contract: string|null}) => (Verdict | Promise)} evaluate * Judge a result — typically `evaluator.evaluate(goal, result, { rubric, contract })`. * @property {string} [contract] - The shared definition of done (A3/D10), forwarded to BOTH `attempt` and * `evaluate` so generator and critic agree on what success means. * @property {number} [maxIterations=3] - Hard cap. The REAL bound is bareguard maxTurns / budget. * @property {boolean} [stopOnPass=true] - Stop on the first satisfied verdict. */ /** * @typedef {object} RefineOutcome * @property {any} result - The last (best available) result. * @property {Verdict|null} verdict - Its verdict. * @property {number} iterations - How many attempts ran. * @property {Array<{result: any, verdict: Verdict}>} history - Every attempt + verdict, in order. */ /** * Thin, Loop-agnostic generate → evaluate → regenerate loop (a port of Managed Agents "Outcomes": * iterate → grade → revise, bounded). Knows nothing about providers or `loop.js`; it drives caller-supplied * `attempt`/`evaluate` until a satisfied verdict, a terminal `failed`, or `maxIterations`. A `HaltError` * thrown by either callback (e.g. a governance cap) propagates as a clean exit — never caught here. * * @param {RefineOptions} options * @returns {Promise} * @when you have a caller-supplied attempt + evaluate pair and want to iterate generate → grade → regenerate until it passes or hits a bound * @fails returns the last outcome on maxIterations or a terminal `failed` verdict (never a faked pass); a HaltError from either callback propagates clean. * @example * const { result, passed } = await refine({ attempt, evaluate, maxIterations: 3 }); * if (!passed) escalate(result); */ export function refine(options: RefineOptions): Promise;