µNorman

Playground

The whole interpreter runs here, compiled to WebAssembly. Models answer from scripts, so programs are deterministic and free, and nothing leaves your machine. Press Run, or Ctrl/⌘ + Enter.

Result
Not run yet.

Cheat Sheet

Definitions and types

(define f (x y) e)a function
(val x e)a binding
(datatype T [K (f τ)] …)a sum type: a value is one of the Ks
(record R (f τ) …)a record; read a field with (. r f)
(Text 400), Num, Bool, Sym, (List τ 8)the askable types; bounds make answers cheaper to reserve

The six agentic forms

(ask m τ ctx 'site)consult a model once, for an answer of type τ
(call κ op args…)use a tool once
(fail φ) / (catch e x h)raise and handle a failure
(budget ([cost $1.00] [time 1min]) e)a money and time limit for everything inside
(workflow ([x e] …) body)named steps; dependencies come from the names each uses
(par e₁ e₂)sugar for a two-step workflow, returning a Pair

Failures

Invalid (the reply didn’t fit the type) · ToolError · Refused · OverBudget · PastDeadline · Raised. retry handles the first two and never the budget ones.

Scripts and tests

(grant m (model [in 3] [out 15] [ceiling 8000]))a model, priced in µ$ per token
(grant py (kernel))a stateful tool
(script s [site (reply "…") (out 20) (latency 2s)])canned replies, keyed by site
(provider-error "503 …"), (refusal "…"), (error "…")injected faults
(under ([script s] [cost $1.00] [time 1min]) …)the world each test runs in
check-expect · check-fail · check-within · check-equiv · check-error · check-assertthe unit-test forms
Two things that will trip you up

Constructors take positional arguments ((Sell "reason")) while records take named ones ((Message [role User] [content "hi"])). And the standard library is very small: there is no number-to-string and no substring yet, so a prompt can only carry text you already have.