Security and composition · ≈ 11 min

A contract that asks for inference

A contract cannot receive a model's answer — but it can commission one deterministically. Including what that primitive does and does not do today.

The earlier lesson said a contract cannot *call* a model, and that is true: no node can re-execute a completion and get the same tokens back. But there is a primitive that is deterministic:

from stdlib import syscalls
task_id = syscalls.ai_enqueue(b"animica/tiny-v1", b"summarise this")

This does not run a model. It commissions one, and returns a task id. Verified in the VM: the same model and prompt always produce the same task id. Every node re-executing the transaction computes the identical id and agrees.

The answer arrives later, off-chain, and reaches the chain in a separate transaction — which some other function of your contract can accept and verify.

This is the shape of every "oracle" pattern, and once you see it you will recognise it everywhere:

1. A transaction commits to a request. Deterministic, cheap, on-chain. 2. Work happens off-chain, where non-determinism is allowed. 3. A later transaction delivers the result, and the contract decides whether to believe it — by signature, by stake, by quorum, by a commitment made before the input was known.

Step 3 is where the actual design work is. ai_enqueue only gets you step 1.

A task id is not an answer. It is a receipt for a request. A contract that treats ai_enqueue as though it returned a completion has a bug that will never surface in testing, because the id it gets back is a perfectly valid 32-byte value that is simply not what it thinks it is.

syscalls also offers quantum_enqueue and blob_pin on the same principle: commit deterministically now, deliver out-of-band later.

And right now, nobody is listening. Read this before you build on it.

syscalls dispatches to a pluggable *provider*, installed by the host via syscalls_api.set_provider(...). As of 2026-08-20, the only callers of set_provider in this entire repository are unit tests. The default is _LocalNoOpProvider, whose ai_enqueue returns "note": "local-noop" and whose read_result is documented as *"results never materialize"* — it returns ready: False forever.

So a contract calling ai_enqueue today gets a well-formed, deterministic receipt for work that no one will ever perform. The commission primitive is real; the delivery side is not yet wired.

The exercise below is still worth doing — the pattern and the determinism property are exactly right, and they are what you will use when the provider lands. Just do not ship a contract that waits on a result. For inference you can actually get today, use the off-chain AICF path: submit through the aicf.* RPC namespace and deliver the result back in a transaction your contract verifies.

Your turn

Implement request(prompt): enqueue an inference job, store the task id under the requesting caller, and return it. Then task_of(addr) reads it back. Enqueueing the same prompt twice must produce the same id — prove it to yourself.

Hints

Stuck? Ask

Answered by Animica's own free inference network. It is donated GPU capacity, so give it 20-30 seconds.