259 lines
8.2 KiB
Markdown
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.
|
|
|
|
---
|