Reasoning
Reflexion
Try, test, write a lesson, try again with it.
Reflexion adds memory of mistakes. The agent attempts the task, an evaluator checks the result, and on failure the agent writes a short lesson in its own words. The next attempt sees every lesson so far.
The evaluator here is real code, four checks on the tweet, so the loop ends on facts, not on the model's opinion of itself.
- Use it when
- You can check the result automatically (tests, rules, a schema)
- Mistakes repeat in recognisable ways
- A few retries are affordable
- Skip it when
- No reliable check exists (the loop just guesses)
- One attempt is usually right
Run it
Scripted model · no key needed · CriogenAI engine in your browserThe runmodel 0 · tools 0
- Press Run to watch the pattern work, step by step.
Try it with your own key optional: a real model makes the decisions; the tools stay simulated
- Your key stays in this tab's memory: not saved, not in cookies or the address bar. Reload or close the tab and it is gone.
- Your browser calls OpenAI directly. Nothing passes through criogenai.com, and nothing is logged.
- Each run makes at most 16 short model calls, billed to your account. Tools, data and side effects are simulated.
This run is the TypeScript code below, running on the CriogenAI engine in your browser (WebAssembly). Without a key, a scripted model stands in for MODEL; with your key, your provider answers, called from this tab. The tools return made-up data.
Build it with CriogenAI
Ready-made:patterns.loop (or review_and_critique)writer = Agent(MODEL, instructions="Write one launch tweet. Follow every lesson you are given.")
reflector = Agent(MODEL, instructions="Say in one line what to do differently next time.")
lessons: list[str] = []
def failures(text: str) -> list[str]: # the evaluator is plain code
checks = {"over 200 characters": len(text) > 200, "no price": "$49" not in text, "hashtags": "#" in text}
return [name for name, failed in checks.items() if failed]
async def attempt(text: str) -> str:
task = f"{text}\nLessons so far: {lessons}" if lessons else text
draft = (await writer.run(task)).text or ""
if failed := failures(draft):
lessons.append((await reflector.run(f"Tweet: {draft}\nFailed: {failed}")).text or "")
return draft
flow = patterns.loop([attempt], until=lambda text, _round: not failures(text), max_iterations=3)
result = await flow.run("Launch tweet for SoundVeil, $49 noise-cancelling headphones.")
print(result.output, result.stop_reason) # "condition" once the checks passconst writer = new Agent({ model: MODEL, instructions: "Write one launch tweet. Follow every lesson you are given." });
const reflector = new Agent({ model: MODEL, instructions: "Say in one line what to do differently next time." });
const lessons: string[] = [];
const failures = (text: string) => // the evaluator is plain code
Object.entries({ "over 200 characters": text.length > 200, "no price": !text.includes("$49"), hashtags: text.includes("#") })
.filter(([, failed]) => failed)
.map(([name]) => name);
const attempt = async (task: string) => {
const draft = (await writer.run(lessons.length ? `${task}\nLessons so far: ${lessons.join("; ")}` : task)).text ?? "";
const failed = failures(draft);
if (failed.length) lessons.push((await reflector.run(`Tweet: ${draft}\nFailed: ${failed}`)).text ?? "");
return draft;
};
const flow = patterns.loop([attempt], (text) => failures(text).length === 0, { maxIterations: 3 });
const result = await flow.run(task);
console.log(result.output, result.stopReason); // "condition" once the checks pass