Enlitt

enlitt() and the standard model

The one public model factory, the one standard model string, and premium wrapping.

enlitt() is the only public model factory this package exports, and "enlitt-standard" (the ENLITT_STANDARD_MODEL constant) is the only standard model string. There is no second factory, no OpenAI-shaped client, and no way to select a personal user, override the standard route's provider, or convert a NANOUSD amount into credit units from application code — all of that is either fixed by Enlitt or belongs on Enlitt's own dashboard.

import { enlitt, ENLITT_STANDARD_MODEL } from "@enlitt/sdk/server";
import { generateText } from "ai";

const result = await generateText({
  model: enlitt(ENLITT_STANDARD_MODEL),
  prompt: "Summarize this support ticket."
});

enlitt() returns an ordinary LanguageModelV3 — the same interface the Vercel AI SDK's own providers implement — so it drops into generateText, streamText, or any other AI SDK call exactly like a direct provider model would.

Two modes, one factory

enlitt()'s first argument decides the mode, and the mode is the argument's type, not a separate flag:

  • enlitt("enlitt-standard") — Enlitt's own standard model. The business never chooses or pays for the underlying provider; Enlitt's own metering applies.
  • enlitt(myProviderModel, options)premium mode: transparent middleware around a provider model the business supplied and pays for itself. Every premium call requires a declared charge (see below); there is no default quote.

Both modes require the business's own application secret, resolved once inside enlitt() through the same path described in Personal login and business credentials. A missing or invalid secret is EnlittConfigurationError, thrown before the first request, identically in both modes — there is no configuration under which enlitt() returns a model that could reach a provider without Enlitt mediating it.

Options

interface EnlittOptions {
  secretKey?: string;       // falls back to ENLITT_SECRET_KEY
  baseUrl?: string;         // falls back to ENLITT_BASE_URL, then the deployed origin
  session?: EnlittSession;  // for callers with no ambient session context
  rateLimit?: EnlittRateLimitRetryOptions;
  onTerminalReportError?: (error: EnlittError) => void;
}

baseUrl is validated once at construction (HTTPS required) rather than per call, and resolves in this order: the option, then ENLITT_BASE_URL, then the deployed Enlitt origin compiled into the package.

Premium wrapping and the declared charge

A premium call declares its own quote through providerOptions.enlitt, passed on the AI SDK call itself:

await generateText({
  model: enlitt(anthropic("claude-opus-5"), { session }),
  prompt,
  providerOptions: {
    enlitt: {
      charge: {
        amount: "1250000",   // exact NANOUSD integer, as a canonical string
        asset: "NANO_USD",
        description: "Ticket summarization"
      }
    }
  }
});
  • charge is required in premium mode and rejected in standard mode — Enlitt's standard route chooses its own model and its own price, so declaring a charge for it is a configuration error, not a no-op.
  • charge.amount is validated as a strictly positive canonical integer string — no sign, fraction, exponent, or leading zero — the same rule the wire itself enforces, and it is carried through unchanged end to end. Nothing in this SDK ever parses a NANOUSD amount into a floating-point Number.
  • charge.asset must be exactly "NANO_USD"; there is no second asset in v1.
  • charge.description is optional and free-text.

Every premium call is managed: there is no "unmanaged" mode and no parameter that opts a call out of Enlitt's admission check. Before the provider is invoked, Enlitt checks the declared charge against the calling user's premium ceiling (see Idempotency and the per-call premium limit); a call that would exceed it is refused with the provider left uninvoked, and the business is never billed for a call Enlitt refused.

See Idempotency for providerOptions.enlitt.idempotencyKey and Typed errors for what a refusal looks like in code.

On this page