UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

68 lines • 3.05 kB
"use strict"; /** * Reflection — iterative self-refinement via critic + revise. * * Paper: "Self-Refine: Iterative Refinement with Self-Feedback" — * Madaan et al., 2023 (https://arxiv.org/abs/2303.17651). * * Pattern: Factory (GoF) → produces a `Runner` built from a `Loop` * whose body is `Sequence(Propose → Critique → Revise)`. * Role: patterns/ layer. Pure composition — no new abstractions. * Emits: Loop's composition.iteration_start / iteration_exit plus * every inner LLMCall's stream.llm_start/end. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.reflection = void 0; const LLMCall_js_1 = require("../core/LLMCall.js"); const Loop_js_1 = require("../core-flow/Loop.js"); const Sequence_js_1 = require("../core-flow/Sequence.js"); /** * Build a Reflection Runner. Each iteration: * 1. Propose — LLMCall writes a candidate answer based on the input * 2. Critique — LLMCall judges the candidate; exit marker stops loop * 3. Revise — next iteration's propose sees the previous critique * * Each iteration's output (the candidate proposal) becomes the next * iteration's input. The final iteration's proposal is returned. */ function reflection(opts) { const stopMarker = opts.untilCritiqueContains ?? 'DONE'; const maxIterations = opts.maxIterations ?? 3; // Each iteration body: Propose → Critique → Revise. The Sequence's // `current` carries whatever the final step returned. const body = Sequence_js_1.Sequence.create({ id: 'refine-body' }) .step('propose', LLMCall_js_1.LLMCall.create({ provider: opts.provider, model: opts.model, ...(opts.temperature !== undefined && { temperature: opts.temperature }), ...(opts.maxTokens !== undefined && { maxTokens: opts.maxTokens }), }) .system(opts.proposerPrompt) .build()) .pipeVia((proposal) => ({ message: `Proposal to critique:\n${proposal}\n\nRespond with critique. When the proposal is good enough, include the marker "${stopMarker}".`, })) .step('critique', LLMCall_js_1.LLMCall.create({ provider: opts.provider, model: opts.model, ...(opts.temperature !== undefined && { temperature: opts.temperature }), ...(opts.maxTokens !== undefined && { maxTokens: opts.maxTokens }), }) .system(opts.criticPrompt) .build()) .build(); // Loop body returns the critic's output; we wrap it so the next // iteration's input gets the ORIGINAL proposal + critique combined, // asking the revisor to improve. The Loop until-guard inspects the // critic response for the stop marker. return Loop_js_1.Loop.create({ name: opts.name ?? 'Reflection', id: opts.id ?? 'reflection', }) .repeat(body) .times(maxIterations) .until(({ latestOutput }) => latestOutput.includes(stopMarker)) .build(); } exports.reflection = reflection; //# sourceMappingURL=Reflection.js.map