AI Models

An AgentModel (in llms/) names a model so workflows can refer to it. There are two types: llm (the default) for llm and loop agents, judges and spec analysis, and decision for the decide engine. tuvl init --preset gemini|openai|anthropic|ollama writes llms/default.yaml and llms/analysis.yaml for you.

LLM models

kind: AgentModel
version: v1
metadata:
  name: default
spec:
  model: gemini/gemini-3.1-flash-lite     # a LiteLLM model id
  api_key: ${GEMINI_API_KEY}             # optional; read from the environment
  temperature: 0.2
  max_tokens: 2048
  timeout: 60
Property Description
model LiteLLM model id: provider/model (required)
api_base Endpoint, for Ollama or a LiteLLM proxy
api_key Use ${ENV_VAR} — secrets live in .env, never in YAML. Without it, the provider's standard variable (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, …) is used
temperature, max_tokens Defaults for calls through this model (an agent's budget.max_tokens still bounds it)
timeout Request timeout in seconds (default 60)
enabled false disables the model; agents that use it fail loudly instead of falling back
Provider Example model
Ollama (local) ollama/llama3.1 with api_base: http://localhost:11434
OpenAI openai/gpt-5.4-mini
Anthropic anthropic/claude-haiku-4-5
Gemini gemini/gemini-3.1-flash-lite
LiteLLM proxy litellm_proxy/<name> with api_base and api_key

Decision models

kind: AgentModel
metadata: { name: triage-classifier }
spec:
  type: decision
  provider: litellm            # laya | jev | litellm
  model: gemini/gemini-3.1-flash-lite

A decision model picks one value of a decide agent's enum output with a confidence; it never writes free text.

Laya (self-hosted). tuvl init --decision-model laya writes this model, LAYA_API_* entries in .env, and a compose.yaml that runs the laya-serve container on localhost:8000 (docker compose up -d laya). tuvl ship adds Laya to the Helm chart (Shipping to production).

The tuvl/laya-serve image comes in two variants:

Tag Checkpoints Memory Use with
<version>-en english about 2 GiB model: english
<version> english + multilingual about 3.5 GiB model: auto or multilingual

tuvl init scaffolds model: english with the -en image, and tuvl ship picks the image (and the Helm memory requests) that matches the model. An -en image has no multilingual weights and runs offline, so non-English text sent to it fails with HTTP 500 inference failed — set model: auto and use the full image when you need other languages.

kind: AgentModel
metadata: { name: laya }
spec:
  type: decision
  provider: laya
  model: english               # english | auto | multilingual | typed-decisions
  api_base: ${LAYA_API_BASE:http://localhost:8000}
  api_key: ${LAYA_API_KEY:}    # optional; an ${ENV_VAR} reference, never a literal key

Jev (hosted). provider: jev with its api_base, and model pinned to a version (jev-1.13.0).

OpenAI-compatible endpoints (a LiteLLM proxy, your own classifier) use provider: litellm with model: openai/<name>, api_base and an ${ENV_VAR} api_key. The endpoint must return {"decision": …, "confidence": 0..1} (or token logprobs); an answer with no confidence is an error, never treated as certain.

See Decide.

Where models are used

Site Field
llm agent llm.model: default (or a LiteLLM id directly)
loop agent loop.model
decide agent decide.model.ref — a decision model or an llm model
Judge artifact spec.model

Model ids are pinned in tuvl.lock by tuvl lock. You can also manage models on the Insight AI Models page.