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
JavaScript
;
/**
* 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