A small library for short reflection conversations with children about things they just made. When a child finishes a piece of work, the companion asks a few questions about it: what took longest, what changed, what they might try next time. It doesn't grade or praise, and it doesn't answer for the child.
This package is only the engine. The split with the host application is strict:
- the engine makes one model call per turn and returns a typed result
- it keeps no state between calls and has no network code of its own
- the host renders everything, names the companion, and stores the history
- all child-facing strings live in the host, none ship from here
- it only asks: no praise, no answers, and nothing but the work and the turns ever reaches the model
The first host is the Sugar Journal, which reaches the engine through the sugar-ai service. SPEC.md is the contract the package is tested against.
The engine is a library; nothing in it runs on its own. A host calls next_turn once per turn, passing the work, the conversation so far, and a provider that talks to a model:
from reflection_engine import ChildTurn, Work, next_turn
turn = next_turn(Work(title="my maze game"), history, provider=provider)
Each call returns one engine turn, or a session end. The host shows the question, appends the child's reply to the history, and calls again.
A provider is any object with the complete method from reflection_engine.provider.Provider. It receives a system prompt, a user message, and a JSON schema, and returns the model's reply decoded against that schema. Working providers for Gemini and OpenRouter-style APIs are in evals/providers.py.
How a turn travels:
A couple of closes return without a model call; SPEC.md has the full flow.
SPEC.md: what the engine guarantees, plus a change log of behavior changes since v1evals/: tools for running the engine against real models, and the measurements behind the spec's claimsexamples/session_trace.jsonl: a made-up two-session trace the test suite validates on every run; a good first look at the wire formatCONTRIBUTING.md: conventions
uv sync
uv run pytest -q
The smoke harness runs scripted children through the engine against a real model:
uv run python -m evals.smoke openrouter google/gemini-3.7-flash
Status: under construction against SPEC.md.