> ## 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.

# Models

> How an agent chooses its model, what a model code looks like, how sampling and reasoning settings apply, and where the catalog comes from

The model is the LLM that reads the prompt and decides what to say and which tools to call. Every agent runs on one. You choose it with the `model` field on [`LuaAgent`](/concepts/agents), or leave the field unset and get the platform default, `alibaba/qwen3.8-flash`. Lua holds the provider accounts; you don't configure a provider key.

## How a model is chosen

A model is named by a model code, `provider/model`, for example `openai/gpt-5.4-mini` or `anthropic/claude-sonnet-5`. `model` accepts that string, or a model resolver: a function that receives the request and returns a code. The resolver runs on every request with the same platform objects a tool has, so it can read `request.channel`, the current end user, or an environment variable and pick accordingly.

```ts src/index.ts theme={null}
import { LuaAgent } from 'lua-cli';

export default new LuaAgent({
  name: 'acme-support',
  persona: 'You are the support agent for Acme.',
  model: (request) => (request.channel === 'whatsapp' ? 'openai/gpt-5.4-mini' : 'anthropic/claude-sonnet-5'),
  modelSettings: { temperature: 0.2, maxOutputTokens: 4096, reasoning: { effort: 'low' } },
});
```

`lua models set --model <code>` writes a code into `src/index.ts` and updates the agent on the server; `lua models unset` removes it and returns the agent to the platform default. Both validate the code against the catalog, as does `lua init --model`. Pushing the agent with `lua push agent` sends the whole agent configuration, so an agent whose code has no `model` clears any model set in the admin dashboard; `lua sync --check` reports that difference before you push. A model or `modelSettings` change takes effect for end users as soon as the push lands, before any agent version is created. The model code is also recorded in each [agent version](/concepts/releases-and-versions), so promoting an older version restores the model it was created with.

The catalog is served by the platform and changes without a CLI release, so read it from the CLI rather than from a page. The `--json` form adds each model's reasoning tiers, accepted media, and web-search support.

```bash theme={null}
lua models list --json --ci
```

```text Output theme={null}
{
  "currentModel": "alibaba/qwen3.8-flash",
  "models": [
    …
    {
      "provider": "alibaba",
      "code": "alibaba/qwen3.8-flash",
      "model": "qwen3.8-flash",
      "displayName": "Qwen3.8 Flash",
      "description": "Qwen 3.8 Flash — 1M context at 0.15/0.47",
      "reasoning": {
        "efforts": [
          "off",
          "low",
          "medium",
          "max"
        ],
        "platformDefault": "low",
        "supported": true
      },
      "media": {
        "image": true,
        "documents": false,
        "audio": false,
        "video": false
      },
      "tools": {
        "webSearch": "bridge"
      },
      "promptCache": {
        "mode": "automatic",
        "minimumCacheTokens": 1024
      },
      "pickerIntents": [
        {
          "intent": "fast"
        }
      ],
      "actionMultiplier": 0.5
    }
    …
  ]
}
```

`actionMultiplier` is the model's cost relative to the platform's baseline model, the same multiplier billing applies to a turn: `0.5` means a turn on this model spends half as much as one on the baseline, `10` means ten times as much. A `costWarning: true` field appears when the multiplier is at or above the platform's warning threshold. `description` is free text from the catalog; the `0.15/0.47` in the default model's line is not defined by the CLI.&#x20;

The CLI has no per-turn readout of the model: `lua logs --type agent_response` records the reply, the channel, and the end user, not the model that produced it. `lua models list` prints `Current model:` as the server has it (or `(platform default)`), and `lua version show <n>` prints the `Model:` a version pins. With a resolver, the model that answered a given turn is not exposed.&#x20;

`modelSettings` tunes how the chosen model answers and applies to every turn. `temperature` (0–2) or `topP` (0–1) control randomness; set one, not both. `maxOutputTokens` caps the reply. `reasoning.effort` sets how much the model thinks before answering, on one scale for every provider: `off`, `minimal`, `low`, `medium`, `high`, `max`. Lua translates it to the provider's own setting and clamps it to the nearest tier that model offers (a model without `off` gets its lowest tier), so any of the six values is safe to send. Left unset, the model's `reasoning.platformDefault` from the catalog applies: `low` on the platform default, `adaptive` on models that decide for themselves. `reasoning.show` controls whether the reasoning trace is returned. `topK`, `presencePenalty`, `frequencyPenalty`, `stopSequences`, and `seed` pass through to providers that support them.

Lua's runtime also contains a fallback chain that can retry a turn on other approved models when the primary's provider fails. It is switched off unless enabled on the server; a model pinned to another provider never inherits the platform-wide chain; and a model served through an organization's own provider key is never re-routed.&#x20;

## A pinned model and a model resolver

A pinned model is one code for every conversation: predictable cost, predictable behavior, one thing to test. A resolver trades that for a decision per request. Use it when the difference is structural (a cheaper model on a high-volume channel, a stronger one for end users on a paid plan) and keep the decision cheap, because it runs before every turn. A resolver that returns a code outside the catalog doesn't fail the turn: Lua substitutes the platform default for that turn, so an unexpected model in the logs usually means a typo in the resolver.

## When to change the model

* The default answers well and cost matters: leave `model` unset.
* Answers need deeper multi-step reasoning or tool use than the default manages: pin a stronger model and keep `reasoning.effort` at `low` until you see the need.
* Some channels or end users justify a different cost profile: a resolver keyed on `request.channel` or `User.get()`.
* The model must read images or documents: check the catalog's `media` flags before pinning.
* Replies run long or vary too much: set `maxOutputTokens` and a lower `temperature` before changing model.

## Limits

* `temperature` 0–2, `topP` 0–1, `maxOutputTokens` at least 1, `stopSequences` an array of strings; out-of-range values throw at construction, for example `Agent modelSettings.temperature must be between 0 and 2`.
* `reasoning.effort` must be one of `off`, `minimal`, `low`, `medium`, `high`, `max`; the model's `reasoning.efforts` list in the catalog says which tiers it offers.
* `lua models set` and `lua init --model` refuse a code that isn't in the catalog.
* A provider refusal (unknown model, quota) surfaces in the CLI as exit code 12.

## Next steps

<Columns cols={2}>
  <Card title="lua models" href="/reference/cli/agents-and-models">List the catalog, set, and unset.</Card>
  <Card title="LuaAgent reference" href="/reference/sdk/luaagent">`model`, `modelSettings`, and their types.</Card>
  <Card title="Execution contexts" href="/concepts/execution-contexts">What a model resolver can read.</Card>
  <Card title="Channels" href="/concepts/channels">The `request.channel` values a resolver sees.</Card>
</Columns>
