Model lists you can read

The chat's model picker shows name, context window (CTX 131K) and an eye
for vision, on shared column tracks; the capability tags are gone from it.
Settings -> Models gives the name its own row and wraps the tags beneath.
The picker's tick now follows an in-place choice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 22:54:31 +00:00
co-authored by Claude Opus 5.5
parent 8503c6c775
commit da43bc1459
10 changed files with 269 additions and 35 deletions
@@ -3,9 +3,16 @@
Model picker.
A real dropdown rather than a <select>, because a <select> cannot show an
image, a description or capability badges -- browsers render only text in an
<option>. The hidden input is what actually carries the value, so the control
still behaves like a form field.
image or an icon -- browsers render only text in an <option>. The hidden
input is what actually carries the value, so the control still behaves like
a form field.
Each option is name, context window and an eye for vision, and nothing else.
It listed every capability switch as a tag until 1.8.2, which is twenty
`tool_*` tags per model in a menu whose one job is choosing; the full list is
on /settings. The options share the list's column tracks (subgrid), so the
context sizes and the eyes line up whatever a name's length -- and every
option emits every slot, empty or not, or its row shifts.
Inside a chat it PATCHes the chat; on /chat it navigates, because there is no
chat row to patch yet.
@@ -31,7 +38,7 @@
</div>
{% endif %}
<div class="picker__list">
<div class="picker__list picker__list--models">
{% for model in models %}
<button class="picker__option {{ 'is-selected' if current_model and model.model_id == current_model.model_id }}"
type="button" role="option"
@@ -39,23 +46,22 @@
data-picker-value="{{ model.model_id }}"
data-picker-search="{{ model.label|lower }} {{ model.model_id|lower }}">
{{ model_avatar(model, cls="picker__avatar") }}
<span class="picker__option-body">
<span class="picker__option-name">
{{ model.label }}
{% if model.pinned %}{{ icon("pin", "icon--sm picker__pin") }}{% endif %}
</span>
{% if model.description %}
<span class="picker__option-desc">{{ model.description }}</span>
{% endif %}
<span class="picker__option-tags">
{% for name, on in (model.capabilities_json or {}).items() %}
{% if on %}<span class="tag">{{ name }}</span>{% endif %}
{% endfor %}
</span>
<span class="picker__option-name">
<span class="truncate">{{ model.label }}</span>
{% if model.pinned %}{{ icon("pin", "icon--sm picker__pin") }}{% endif %}
</span>
{% if current_model and model.model_id == current_model.model_id %}
{{ icon("check", "icon--sm picker__tick") }}
{% endif %}
<span class="model-ctx mono"
{% if model.context_length %}title="{{ t('Context window') }}: {{ model.context_length }}"{% endif %}>
{%- if model.context_length %}CTX {{ model.context_length|context_size }}{% endif -%}
</span>
<span class="model-vision">
{%- if (model.capabilities_json or {}).get("vision") -%}
{{ icon("eye", "icon--sm") }}<span class="visually-hidden">{{ t("Sees images") }}</span>
{%- endif -%}
</span>
{# Always rendered and shown by `.is-selected`, so it follows ui.js's
in-place choice rather than staying on the model the page loaded with. #}
<span class="picker__tick">{{ icon("check", "icon--sm") }}</span>
</button>
{% endfor %}
</div>