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-assert | the 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.