Evolving Agents Labs

Evolving Agents Labs/Experiments/token-trie

token-trie

What if a small model could not emit invalid syntax, because the decoder refused to let it?

Reproducible May 2026
Legal instruction paths continue; everything else dead-ends

Constraint in the decoder, not the prompt

Asking a model nicely for valid output is a request. Every markdown-skill ecosystem trusts the model to comply and then repairs the JSON when it does not.

The alternative is to make the invalid token unreachable. Every legal instruction is tokenized once with the live model's tokenizer and inserted into a trie of token-ID sequences. At each decoding step the sampler intersects the trie's valid-next set with the logits and picks the highest-probability token that the trie allows. Malformed output is not discouraged; it has no path.

Downstream, that pays off immediately — dispatch.js parses with a plain regex. No JSON repair, no schema retry, no validation layer.

The model ratifies; it does not plan

This is the part usually left out. In the Tetris demo, a hand-written program layer enumerates all forty placements, simulates them and scores them with Dellacherie weights. The model is handed the ranked options and picks. It is the decoder and the selector — not the planner.

That is a real and useful result about what a 350M model can be trusted with. It is not "a small model runs an OS", and the repo should not be read as claiming that. The cost is that every skill needs a planner written behind it.

What's proven

Clone it, serve it, watch it. No API key, no build step, no account.

cd mobile/public && python3 -m http.server 8000

LFM 2.5 350M loads through wllama and plays. The kernel is five dependency-free ES modules, roughly 400 lines. First load downloads ~230 MB of weights; after that it is instant.

The three limits, stated plainly. Opcodes must be declared as complete literal strings — the Tetris cartridge enumerates {"action":"left"} and its four siblings — so the model cannot emit an argument a human did not pre-write. Trie-driven argument synthesis is the missing piece and the real critical path. Second, this works because LFM 2.5 tokenizes the opcode markers as single tokens; Qwen and Gemma split them, the trie's valid set stops intersecting top-K, and output stays syntactically valid while ceasing to be strategic. Third, one cartridge per session — there is no registry yet.

← skillos_robot  ·  evolving-memory →