This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/models.md
2026-03-13 00:31:05 +00:00

259 lines
8.2 KiB
Markdown

# Models & Preferences
What models are available to the current user and how they control
visibility.
---
### Enabled Models
The primary endpoint for populating model selectors:
```
GET /models/enabled
```
Returns a composite response:
```json
{
"data": [ UserModel, ... ],
"default_model": "claude-sonnet-4-20250514"
}
```
`default_model` is the admin-configured default model ID (from the
`default_model` policy). Empty string if unset.
**UserModel object:**
```json
{
"id": "composite-id",
"display_name": "Claude Sonnet 4",
"model_id": "claude-sonnet-4-20250514",
"model_type": "chat",
"source": "catalog",
"provider_config_id": "uuid",
"config_id": "uuid",
"provider_name": "Anthropic",
"provider_type": "anthropic",
"capabilities": {
"streaming": true,
"tool_calling": true,
"vision": true,
"thinking": true,
"reasoning": false,
"code_optimized": false,
"web_search": false,
"max_context": 200000,
"max_output_tokens": 8192
},
"is_persona": false,
"persona_id": "",
"persona_handle": "",
"persona_scope": "",
"persona_avatar": "",
"persona_team_name": "",
"description": "",
"icon": "",
"avatar": "",
"system_prompt": "",
"temperature": null,
"max_tokens": null,
"tool_grants": [],
"pricing": {
"input_per_m": 3.00,
"output_per_m": 15.00,
"currency": "USD"
},
"scope": "global",
"owner_id": null,
"team_name": "",
"hidden": false,
"sort_order": 0,
"provider_status": "healthy"
}
```
**Field reference:**
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Composite key. Catalog: `{config_id}:{model_id}`. Persona: persona UUID. |
| `display_name` | string | Human-readable name (from catalog or persona). |
| `model_id` | string | Raw model identifier (e.g. `claude-sonnet-4-20250514`). |
| `model_type` | string | `"chat"`, `"embedding"`, `"image"`, etc. |
| `source` | string | `"catalog"` (DB catalog entry) or `"persona"`. |
| `provider_config_id` | string | UUID of the provider config that serves this model. |
| `config_id` | string | Alias of `provider_config_id` (frontend compat). |
| `provider_name` | string | Display name of the provider config. |
| `provider_type` | string | Provider type slug (e.g. `"anthropic"`, `"openai"`). |
| `capabilities` | object | Nested `ModelCapabilities` — see below. |
| `is_persona` | bool | `true` if this entry is a Persona, not a raw model. |
| `persona_id` | string | Persona UUID (omitted if not a persona). |
| `persona_handle` | string | `@handle` for mention routing (omitted if not a persona). |
| `persona_scope` | string | Persona scope: `"global"`, `"team"`, `"personal"` (omitted if not). |
| `persona_avatar` | string | Avatar URL (omitted if not a persona or unset). |
| `persona_team_name` | string | Owning team name for team-scoped personas (omitted if N/A). |
| `description` | string | Persona description (omitted if empty). |
| `icon` | string | Persona icon (omitted if empty). |
| `avatar` | string | Avatar URL (omitted if empty). |
| `system_prompt` | string | Persona system prompt (omitted if empty). |
| `temperature` | float\|null | Persona temperature override. |
| `max_tokens` | int\|null | Persona max-tokens override. |
| `tool_grants` | string[] | Tool IDs granted to this persona. |
| `pricing` | object\|null | Nested `ModelPricing` — see below. Omitted if unavailable. |
| `scope` | string | `"global"`, `"team"`, or `"personal"`. |
| `owner_id` | string\|null | Owner user/team ID for team/personal scoped entries. |
| `team_name` | string | Team name (persona entries only). |
| `hidden` | bool | `true` if the user has hidden this model via preferences. |
| `sort_order` | int | User's custom sort position (0 = default). |
| `provider_status` | string | Health status: `"healthy"`, `"degraded"`, `"down"`, `"unknown"`, or empty. |
**ModelCapabilities:**
| Field | Type | Description |
|-------|------|-------------|
| `streaming` | bool | Supports streaming responses. |
| `tool_calling` | bool | Supports function/tool calling. |
| `vision` | bool | Supports image inputs. |
| `thinking` | bool | Supports extended thinking. |
| `reasoning` | bool | Reasoning-optimized model. |
| `code_optimized` | bool | Code-optimized model. |
| `web_search` | bool | Has built-in web search. |
| `max_context` | int | Context window size in tokens. |
| `max_output_tokens` | int | Maximum output tokens. |
Capabilities are resolved through the three-tier chain: catalog DB →
heuristic inference → admin overrides (see `providers.md` §capabilities).
**ModelPricing:**
| Field | Type | Description |
|-------|------|-------------|
| `input_per_m` | float | Input cost per million tokens. |
| `output_per_m` | float | Output cost per million tokens. |
| `currency` | string | Currency code (e.g. `"USD"`). |
**Persona inheritance:** When `is_persona` is `true`, the `capabilities`
and `pricing` objects are inherited from the persona's underlying base
model. The persona adds identity (name, handle, avatar, system prompt,
tool grants) — not capability restrictions. Persona entries always have
`hidden: false`; persona visibility is controlled by the grant system
and the `is_active` flag, not by model preferences.
**Model allowlist filtering (v0.24.2):** Non-admin users whose groups
define model restrictions will only see models in their allowlist.
Persona entries whose underlying `model_id` is not in the allowlist are
also filtered. Admins bypass this filter entirely.
**Visibility resolution order:**
1. Global catalog: enabled models → all authenticated users
2. Team catalog: enabled models → team members
3. Personal BYOK: enabled models → owner (requires `allow_user_byok` policy)
4. Personas: global + team + personal + shared-via-grants
5. User hidden preferences applied last (sets `hidden` flag, does not remove)
6. Model allowlist filtering (removes entries entirely for non-admins)
---
### User Model Preferences
Users can hide models they don't want to see and set per-model
defaults. Preferences are keyed on the **composite identity**
`provider_config_id:model_id` — the same model from different
providers can have independent visibility.
```
GET /models/preferences → { "data": [PreferenceEntry, ...] }
PUT /models/preferences ← { "model_id": "...", "provider_config_id": "uuid", ... }
POST /models/preferences/bulk ← { "entries": [...], "hidden": bool }
```
**GET /models/preferences**
Returns all preference entries for the authenticated user.
PreferenceEntry:
```json
{
"id": "uuid",
"user_id": "uuid",
"model_id": "grok-4.1-fast",
"provider_config_id": "uuid",
"hidden": true,
"preferred_temperature": 0.7,
"preferred_max_tokens": 4096,
"sort_order": 0,
"created_at": "2025-06-15T14:30:00Z",
"updated_at": "2025-06-15T14:30:00Z"
}
```
**PUT /models/preferences**
Upserts a single preference entry. All fields except `model_id` are
optional — only provided fields are updated. If no entry exists, one
is created.
Request body:
```json
{
"model_id": "claude-sonnet-4-20250514",
"provider_config_id": "uuid",
"hidden": true,
"preferred_temperature": 0.7,
"preferred_max_tokens": 4096,
"sort_order": 1
}
```
`model_id` and `provider_config_id` are required. All other fields are
optional — only provided fields are updated. If no entry exists, one
is created.
Returns `{ "message": "preference updated" }`.
**POST /models/preferences/bulk**
Sets the hidden state for multiple model+provider pairs at once. The
`hidden` value is applied to **all** entries in the batch — this is
not per-entry hidden control.
Request body:
```json
{
"entries": [
{ "model_id": "grok-4.1-fast", "provider_config_id": "uuid" },
{ "model_id": "llama-3.1-70b", "provider_config_id": "uuid" }
],
"hidden": true
}
```
Returns `{ "message": "preferences updated", "count": 2 }`.
**Identity rule:** `provider_config_id` is required on write. The same
bare `model_id` from two different provider configs (e.g. global Venice
vs personal BYOK Venice) are independent preference entries. The
frontend composite ID format is `{provider_config_id}:{model_id}`.
**Persona preferences:** Personas are not in this table. A persona's
visibility is controlled by the grant system and the `is_active` flag,
not by model preferences.
---