Skip to content

Model selector

A picker for the provider and model a conversation uses, grouped by provider, searchable, for apps where the reader brings their own key or picks a model.

  • <aparte-model-selector>
  • @aparte/plugin-model-selector
On this page
Open

<aparte-model-selector> lists the providers your config knows, one group per provider, with the models each one fetches; a provider with no list to fetch, such as the Vercel AI SDK bridge, is left out. With a single provider it is a flat list. With persist, the choice is what the next message is sent to: the pick is written into the config. Without it, the element only sends aparte-model-change, for code of yours to act on.

It is built on core’s select, and it reads the config of the chat it sits in, so two chats on one page each list their own models.

bash
npm install @aparte/plugin-model-selector @aparte/core
ts
import '@aparte/plugin-model-selector'; // registers the element

Its place is the composer’s toolbar. margin-inline-start: auto pushes it to the end of the row; the four framework wrappers take it through their toolbar slot (see the composer toolbar).

html
<aparte-composer-toolbar>
  <aparte-model-selector auto-select persist searchable style="margin-inline-start: auto"></aparte-model-selector>
</aparte-composer-toolbar>

The plugin types its own element, one subpath per framework, so the tag is checked as soon as you import that subpath once:

Nothing to import: the tag is in HTMLElementTagNameMap once the plugin is imported, and aparte-model-change is typed through HTMLElementEventMap.

html
<aparte-model-selector persist searchable placeholder="Pick a model"></aparte-model-selector>

Outside Angular, a presence attribute is '' to set and null to remove, never false (the rule). The framework packages are optional peer dependencies: you carry only the one you use.

The list loads asynchronously, so for a moment the chat can be mounted with no model chosen. To keep the composer from sending until one is:

ts
import { aparteGlobalConfig } from '@aparte/core';

aparteGlobalConfig.setRequireModelSelection(true);

The composer greys out and comes back once auto-select, or the reader, picks a model.

<aparte-model-selector> · class AparteModelSelector

Attributes

AttributeDescription
persistWrites the selection back through the config, so it survives a reload.
auto-selectSelects the first model as soon as one is available.
searchableAdds the dropdown’s filter field.
placeholderOverrides the text shown while nothing is selected.
disabledDisables the picker. Inside an <aparte-composer> it also follows the composer’s own disabled, so a disabled composer does not leave its model picker operable.

Properties

PropertyTypeDescription
providerId (readonly)string | nullCurrent provider ID.
modelId (readonly)string | nullCurrent model ID.

Methods

MethodDescription
aparteConfigChanged(next: AparteConfig): voidThe boundary above us appeared or changed: move the subscription and reload, because a different config means different providers and a different selection. See AparteConfigAware. The element’s own per-instance tests passed before this existed only because they mount the boundary FIRST — the one ordering no wrapper produces.
setSelection(providerId: string, modelId: string): voidProgrammatically set the selection.

Events

EventTypeDescription
aparte-model-changeCustomEvent<AparteModelChangeEventDetail>The provider or the model changed; carries both ids.
  • The button is named by its placeholder and the current model, and opens a list box; searchable adds a filter field.
  • Providers are option groups, so a screen reader names the provider of each model.
  • Approval mode — the other switch that lives in the toolbar.
  • Composer — the toolbar it sits in.
  • Select — the control it is built on.