criogenai

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 browser
Ready
failretrypassTaskAttemptChecksReflectLessonsAnswer
The runmodel 0 · tools 0
  1. 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 pass
const 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