Skip to content

Model catalog

For the administrator workflow, see Manage models. This page describes the version-1 JSON document and its runtime behavior.

Document format

A minimal catalog for an existing local model server:

{
  "version": 1,
  "default_model": "local-assistant",
  "models": [
    {
      "id": "local-assistant",
      "label": "Local assistant",
      "provider": "local",
      "wire_api": "openai_chat",
      "api_model": "your-server-model-id"
    }
  ]
}

Replace api_model with the ID served by your endpoint. This example declares a text-only model without reasoning. Set capabilities to match your model before using reasoning or multimodal inputs.

Top-level field Required value
version Integer 1
default_model ID of an enabled entry in models
models Between 1 and 1,000 model entries

Unknown fields are rejected at both document and model level.

Model fields

Field Default Meaning
id Required Stable Numi identifier stored by chats; 1–256 characters, no whitespace or control characters
label Required Display name; 1–160 characters
provider Required Provider settings to use; see Providers
wire_api openai_chat openai_chat, openai_responses, or anthropic_messages
api_model null Upstream ID; falls back to id
hint Empty string Short description, up to 1,000 characters
enabled true Whether users can select the entry when its provider is configured
input_modalities [] Unique non-text inputs from image, video, audio; text is implicit
context_window null Token window, at least 1,024; overrides the provider fallback for request budgeting and compaction
supports_prompt_cache false Whether Numi should apply supported prompt-cache handling
supports_reasoning false Enables reasoning capabilities
reasoning_mode none Request control: native, effort, enabled, or none
preserve_reasoning false Requests replay of returned reasoning where the wire protocol supports it
reasoning_mandatory false Prevents disabling reasoning
reasoning_efforts [] Unique effort names supported by the route
reasoning_default_effort null Default effort; must belong to the list when a list is given
reasoning_default_enabled null Provider's default reasoning state

IDs must be unique. Routes must also be unique by (provider, wire_api, api_model or id). Keep IDs stable once chats reference them; disable a referenced model instead of deleting it.

context_window is supported in catalog JSON, model creation, and imports. The current Models form and per-model update schema do not expose it; use an import or edit the complete private JSON document to change it.

Schema validation does not check endpoint health or every provider/protocol pairing. anthropic_messages uses the anthropic or anthropic_compat settings; select the matching provider for that wire API.

Non-reasoning entries use reasoning_mode: "none" and cannot declare preservation, mandatory reasoning, or effort metadata. Reasoning entries must choose a different mode. Mandatory reasoning cannot be disabled by default.

For OpenRouter, use discovery or Refresh provider metadata in the Models page to populate supported levels. Numi's chat setting uses off to disable optional reasoning; it is not an effort to advertise for a mandatory model. See Reasoning effort and Preserved reasoning for request, storage, and replay behavior.

Packaged models overview

The current packaged entries live in src/numi_chat/llm/models.default.json. Inspect that file or the Models page for model IDs and capabilities. Provider discovery can refresh advertised metadata; a model description is not a remote availability check.

State Meaning
Configured An entry exists in the active catalog
Enabled The operator has enabled the entry
Available Its provider settings exist
Selectable It is enabled and its provider is available

Disabled entries remain resolvable for history. Provider availability does not prove endpoint health or change the configured default.

Catalog precedence and persistence

The packaged file is application data. If NUMI_CHAT_MODEL_CONFIG_PATH exists, that private file is the complete catalog; it is not merged with packaged defaults. The path defaults to state/models.json, or /app/state/models.json in Docker.

Admin writes validate the document and atomically replace the private file before activating a new snapshot. Invalid private JSON prevents startup; an invalid runtime reload leaves the last known-good snapshot active. Credentials and base URLs remain in environment settings, not catalog exports.

Each process checks the private file revision while reading the catalog. Writers are serialized only within one process; separate containers need a shared state directory to observe the same file. Mount the complete state directory so atomic replacement works.