infer functions
An infer function is an LLM-backed function. Calling it runs nothing; it returns a lazy, thenable Intent<T>, and resolving that intent — with ask from another infer function or await from plain TypeScript — is what runs the inference.
Three declaration forms
Section titled “Three declaration forms”infer function summarize(.text: string) { return ask ..`a one-sentence summary`<string>;}
export infer function classify(.message: string) { return ask ..`the category of the message`<string>;}
export infer function triage`triage the ticket like a support lead`(.ticket: string) { return ask ..`the severity: low, medium or high`<"low" | "medium" | "high">;}The third form carries an instruction marker: a template literal between the name and the parameter list. Its text is the function’s instruction — guidance that applies to every ask in the invocation. ${expr} holes interpolate lexical values into the instruction; a ${.member} hole turns the marker into a prompt template for the function’s context block (see Prompt templates).
-
Top-level function declarations only.
inferon a method, an arrow function or a function expression is reserved for a later version (NOLA1004); a declaration nested in another function isNOLA2003. -
Never
async.async infer functionis a parse error — an infer function is implicitly awaitable throughIntent. -
awaitis legal in the body, for ordinary promises: fetch, a database, any library.enrich.tsi export infer function enrich(.handle: string, fetchProfile: (h: string) => Promise<string>) {const profile = await fetchProfile(handle); // ordinary promisereturn ask ..`the person's job title from: ${profile}`<string>;} -
askonly directly inside the body — not at module level, not inside a nested closure, not even one written inside the infer function (NOLA2001). -
Export by name.
export default infer functiondoes not parse; writeexport infer function f(…)and let consumers import the name.
Return type
Section titled “Return type”Leave the return type off and let it infer — every example in the repository does. When you do annotate, the annotation is Intent<T>: the body returns a T, the way an async function body returns T under Promise<T>.
import type { Intent } from "@nola-lang/runtime";
interface User { name: string;}
export infer function getUser(.message: string): Intent<User> { const user = ask ..`the user described in the message`<User>; return user;}Do not annotate it Promise<T>: Intent<T> is PromiseLike<T>, not a Promise, so nola check reports TS2739 (missing catch, finally, [Symbol.toStringTag]).
Calling from plain TypeScript
Section titled “Calling from plain TypeScript”import { classify, triage } from "./forms.tsi";
const category = await classify("My card was charged twice.");const severity = await triage("Checkout is down for every customer in the EU.");console.log(category, severity);await on the returned intent opens an invocation and runs it. The intent also carries a few methods you can chain before awaiting — .withTimeout(ms), .detached(), .withProvider(…) and more — described in Intent methods.
Next: Contextual parameters