> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# AI

> Isolated text generation with any catalog model, outside the agent's chat pipeline

`AI.generate` runs one model call with a prompt you supply and returns the text or the full result. The call skips the [agent](/concepts/agents)'s persona, skills, and processors; to run a whole turn of an agent, use [`Agents.invoke`](/reference/sdk/agents). Available in tools, jobs, webhooks, triggers, processors, and workflow code steps.

*Verified against lua-cli 3.33.0.*

```ts theme={null}
import { AI } from 'lua-cli';
```

## Quick example

The short form returns text; the options form returns the full result.

```ts theme={null}
import { AI } from 'lua-cli';

const ticketBody = 'Login fails after the password reset email arrives.';
const summary = await AI.generate('Reply in one sentence.', [{ type: 'text', text: ticketBody }]);

const result = await AI.generate({
  model: 'google/gemini-3.8-flash',
  system: 'You are concise.',
  prompt: 'What is the weather in London today?',
});
```

## Methods

### generate(prompt, content?)

Generates text and returns it as a string.

```ts theme={null}
AI.generate(prompt: string, content?: UserContent): Promise<string>
```

<ParamField path="prompt" type="string" required>
  The user prompt when called alone. When `content` is given, the system instruction instead.
</ParamField>

<ParamField path="content" type="UserContent">
  The user message: a string, or an array of AI SDK v5 parts. Parts are `{ type: 'text', text }`, `{ type: 'image', image, mediaType? }`, and `{ type: 'file', data, mediaType, filename? }`, where `image` and `data` are a URL string, a base64 string, or a `Buffer`.
</ParamField>

**Returns** — the generated text, the same value as `text` on the options form.

**Example**

```ts theme={null}
import { AI } from 'lua-cli';

const description = await AI.generate('Describe the photo in two sentences.', [
  { type: 'text', text: 'What is in this photo?' },
  { type: 'image', image: 'https://example.com/photo.jpg', mediaType: 'image/jpeg' },
]);
```

**Errors** — the same as `generate(options)`.

### generate(options)

Generates text with explicit model settings and returns the full result.

```ts theme={null}
AI.generate(options: AiGenerateInput): Promise<AiGenerateOutput>
```

<ParamField path="model" type="string" default="alibaba/qwen3.8-flash">
  A [model code](/concepts/models) in `provider/model` form, as listed by `lua models list`. Defaults to the platform default model, not to the agent's model. A code the platform doesn't approve falls back to the default.
</ParamField>

<ParamField path="system" type="string">
  System instruction.
</ParamField>

<ParamField path="prompt" type="string">
  Plain user prompt. Pass `prompt` or `messages`, not both.
</ParamField>

<ParamField path="messages" type="ModelMessage[]">
  AI SDK v5 messages, `{ role, content }`, with the same part shapes as `content` on the short form. The server validates them; a malformed part is rejected with a 400 that names its path, such as `messages[0].content[1]`.
</ParamField>

<ParamField path="temperature" type="number">
  Sampling temperature. The accepted range is the provider's.
</ParamField>

<ParamField path="maxOutputTokens" type="number">
  Maximum number of tokens to generate.
</ParamField>

<ParamField path="structuredOutput" type="{ schema: AiGenerateJsonSchema }">
  A JSON Schema the response must match; the parsed object lands on `output`. The schema needs a top-level `type: "object"`. On Google models, setting it turns Google Search grounding off for that call.
</ParamField>

**Returns**

<ResponseField name="result" type="AiGenerateOutput">
  Optional fields are omitted when empty.

  <Expandable title="properties">
    <ResponseField name="text" type="string">
      The generated text.
    </ResponseField>

    <ResponseField name="finishReason" type="FinishReason">
      One of `stop`, `length`, `content-filter`, `tool-calls`, `error`, `other`, `unknown`.
    </ResponseField>

    <ResponseField name="usage" type="LanguageModelUsage">
      `inputTokens`, `outputTokens`, `totalTokens`, and optionally `reasoningTokens` and `cachedInputTokens`. Each is `undefined` when the provider doesn't report it.
    </ResponseField>

    <ResponseField name="output" type="unknown">
      The parsed JSON when `structuredOutput` was set and `finishReason` is `stop`. It is parsed, not validated against the schema; validate it yourself.
    </ResponseField>

    <ResponseField name="sources" type="AiGenerateSource[]">
      Google Search grounding sources, Google models only: `{ sourceType: 'url', id, url, title? }`.
    </ResponseField>

    <ResponseField name="reasoning" type="ReasoningOutput[]">
      Reasoning steps when the model exposes them; `reasoningText` is their concatenation.
    </ResponseField>

    <ResponseField name="toolCalls" type="AiGenerateToolCall[]">
      Tool calls the model made, `{ type: 'tool-call', toolCallId, toolName, input }`. `toolResults` holds the matching `{ type: 'tool-result', toolCallId, toolName, output, isError? }` entries.
    </ResponseField>

    <ResponseField name="warnings" type="CallWarning[]">
      Provider warnings, for example an unsupported setting.
    </ResponseField>
  </Expandable>
</ResponseField>

**Example**

```ts theme={null}
import { AI } from 'lua-cli';
import { z } from 'zod';

const ticketBody = 'Login fails after the password reset email arrives.';
const SentimentSchema = z.object({
  sentiment: z.enum(['positive', 'negative', 'neutral']),
  score: z.number().min(0).max(1),
});

const result = await AI.generate({
  system: 'Classify the sentiment of the message.',
  prompt: ticketBody,
  temperature: 0,
  structuredOutput: {
    schema: {
      type: 'object',
      properties: {
        sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
        score: { type: 'number', minimum: 0, maximum: 1 },
      },
      required: ['sentiment', 'score'],
    },
  },
});

const parsed = SentimentSchema.safeParse(result.output);
```

**Errors** — the call throws an `Error`:

* Invalid input: `structuredOutput.schema must be a JSON Schema with top-level type "object"`, or a malformed `messages` part. Fix the request; retrying doesn't help.
* The provider refused the request as sent (a model the provider doesn't serve, a refused prompt): the platform reports it as `PROVIDER_REJECTED` with `transient: false`. Retrying unchanged fails the same way.
* The provider is unavailable (408, 429, 5xx, or no answer): the platform retries on the next model in its fallback chain. When every model fails, a deployed agent sees `Every model in the fallback chain failed`; `lua test` sees the platform's `UPSTREAM_UNAVAILABLE` error, `… is temporarily unavailable — retry in a moment`.
* No message from the server: `AI generation failed`.

## Types

`AiGenerateInput`, `AiGenerateOutput`, `AiGenerateStructuredOutput`, `AiGenerateJsonSchema` (a `Record<string, unknown>`), `AiGenerateSource`, `AiGenerateToolCall`, and `AiGenerateToolResult` are exported from `lua-cli`. `UserContent`, `ModelMessage`, `FinishReason`, `LanguageModelUsage`, `ReasoningOutput`, and `CallWarning` are the AI SDK v5 types of the same names; you don't need to import them to call `AI.generate`.

## See also

* [`Agents`](/reference/sdk/agents) — run a full turn of an agent instead of a bare model call
* [`CDN`](/reference/sdk/cdn) — read stored files into `image` and `file` parts
* [About models](/concepts/models) — model codes, the platform default, and `lua models list`
* [Compose agents](/build/compose-agents) — when to use `AI.generate` and when to invoke an agent
