{% from "_macros.html" import icon, model_avatar %} {# Model picker. A real dropdown rather than a , because a cannot show an image or an icon -- browsers render only text in an . 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. #} {% if current_model %} {{ model_avatar(current_model, cls="picker__avatar") }} {{ current_model.label }} {% else %} {{ t("Choose a model") }} {% endif %} {{ icon("chevron-down", "icon--sm picker__chevron") }} {% if models|length > 8 %} {% endif %} {% for model in models %} {# The avatar in a slot of its own size, carrying the load-state dot on its corner. A dot there takes no track, so the columns the context sizes and the eyes line up on are the ones they had. The state is fetched when the menu opens (ui.js, /api/models/state) rather than rendered here: it changes by the minute, and asking every endpoint on every page render would put a network call in front of each page. #} {{ model_avatar(model, cls="picker__avatar") }} {{ model.label }} {% if model.pinned %}{{ icon("pin", "icon--sm picker__pin") }}{% endif %} {%- if model.context_length %}CTX {{ model.context_length|context_size }}{% endif -%} {%- if (model.capabilities_json or {}).get("vision") -%} {{ icon("eye", "icon--sm") }}{{ t("Sees images") }} {%- endif -%} {# 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. #} {{ icon("check", "icon--sm") }} {% endfor %} {{ t("No model matches that.") }} {% if chat %} {# Changing the value fires the PATCH; htmx serialises the hidden input. #} {% else %} {# No chat yet: selecting navigates so the whole composer re-renders with the right vision warning and the right hidden model_id. #} {% endif %}
{{ t("No model matches that.") }}