Skip to content

Introduction

Nola adds syntax to TypeScript for asking a language model for a typed value. You write .tsi files using TypeScript types, functions and control flow, with infer function and ask for inference. Nola compiles these files to plain TypeScript so they can work with the rest of your application.

analyze.tsi
export infer function analyzeUserRequest(userId: string, .message: string) {
const ticketId = ask `ticket id mentioned in the message`: string;
const isFraud = ask `does the message look fraudulent`: boolean;
return { userId, ticketId, isFraud };
}

Plain TypeScript imports the .tsi file directly and awaits the result:

main.ts
import { analyzeUserRequest } from "./analyze.tsi";
const result = await analyzeUserRequest("user-1", "Ticket TCK-4711: customer reports suspicious activity.");
// → { userId: "user-1", ticketId: "TCK-4711", isFraud: true }

.message is a contextual parameter: its value is available to every ask in this invocation. userId is a plain argument. Its name appears in the function signature shown to the model, but its value is not included automatically.

  • infer function declares a function that can use inference. Calling it returns a lazy, thenable Intent<T>; awaiting the intent runs the function. Parameters that start with a dot, such as .message, supply context to its asks.
  • ask resolves an intent the way await resolves a promise. An extractor, ask `instruction`: T, asks the model for a T. A call intent, such as ask fn`hint`(...), lets the model fill extractor arguments before running the function. ask with <name> … selects a named model from nola.config.ts.

Nola keeps the result type, request and context in your source code. It derives the response schema from the TypeScript type, validates the model’s reply at runtime and shares contextual parameters across asks in a function. You can use try/catch, loops and helper functions around an ask as you would around other asynchronous work.

This requires Nola’s compiler, loader or bundler plugin, and editor support for .tsi. Why Nola explains that tradeoff; the comparison pages show the same tasks in Nola, BAML, the Vercel AI SDK and LangGraph.

Piece Package
CLI — nola init / build / run / check / declarations / skill and the Node loader (node --import nola-lang/register) nola-lang
Runtime — Intent<T>, defineConfig, telemetry and receipts @nola-lang/runtime
Providers — openai, anthropic, google, mockProvider, withRetry, fallback, roundRobin, record/replay @nola-lang/providers
Scaffolder create-nola-lang (alias create-nola)
Bundler plugins — Vite, webpack, Rollup, Rolldown, esbuild, Rspack, Next.js @nola-lang/vite, @nola-lang/webpack, …
Editor — tsserver plugin, language server, VS Code extension nola.nola-vscode

Diagnostics are numbered NOLA1xxx (parse), NOLA2xxx (compile), NOLA3xxx (runtime) and NOLA4xxx (bundler).

Next: Quick start — scaffold a project and run your first .tsi file offline.