Modelos

La página Modelos de los ajustes de un producto de IA. Un modelo predeterminado con su contexto, velocidad y coste de un vistazo, un esfuerzo predeterminado que sabe qué admite cada modelo, una lista de modelos con búsqueda agrupada por proveedor con filtros, fijados e interruptores masivos, servidores compatibles con OpenAI con una prueba de conexión real y una actualización que te dice qué hay de nuevo.

Todo producto de IA acaba teniendo una página de Modelos: qué modelos aparecen en el selector, con cuál empiezan los chats nuevos, cuánto piensa y qué modelo pequeño ejecuta las tareas en segundo plano. Models es esa página como un solo componente, ModelSettings, que se integra en cualquier sección de Ajustes y guarda a través de la misma isla que el resto de tus ajustes.

Default model abre un menú de los modelos activados, agrupados por proveedor, cada uno con su contexto, coste y capacidades. Bajo el selector, unos chips muestran la ventana de contexto, la velocidad y el coste del modelo elegido, para que el compromiso sea visible antes de abrir un chat. Default effort usa el control deslizante de esfuerzo de Prompt Input y sabe lo que admite el modelo predeterminado. Si arrastras más allá de lo que puede hacer, el control se detiene en su nivel más alto, la línea de debajo explica por qué y los lectores de pantalla también lo oyen. Los modelos que no razonan atenúan el control y explican que el esfuerzo no se aplica.

La lista de modelos busca por nombre, proveedor y capacidad, y filtra por Enabled, Reasoning, Fast o Vision. Los modelos se agrupan por proveedor con un recuento de los activados y un switch para activar o desactivar un proveedor entero. Cada fila muestra el contexto, una escala de coste de cuatro puntos e insignias para New y Preview. Fija los modelos que más usas desde el menú de una fila y pasan a un grupo Pinned arriba, en el orden en que los muestra el selector. Muévelos con Move up y Move down, o con Alt y las teclas de flecha, sin arrastrar nada.

Add model conecta cualquier servidor compatible con OpenAI, incluidos los locales. Comprueba la URL, señala un modelo que ya añadiste y prueba la conexión antes de añadir, mostrando cuánto tardó el servidor en responder o el motivo del fallo. El campo de clave oculta la clave hasta que la muestres. Refresh pide a tu servidor el catálogo más reciente y muestra un banner discreto como "2 new models: Nova 3.5 and Atlas 2 Vision", con Show para filtrar por ellos. Los modelos nuevos llegan desactivados, así que nada cambia en el selector hasta que elijas.

Task models da al subagente de exploración, a los títulos de chat y a los resúmenes su propio modelo, o Auto. Nada se guarda hasta que guardas: cada cambio hace aparecer la barra de guardado de Settings, Discard lo devuelve todo, incluidos los modelos personalizados eliminados, y el modelo predeterminado no se puede desactivar por accidente.

  1. Añade el registro Pro a components.json

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. Añade tu token

    Crea un token en tu página de cuenta y colócalo en .env.local como HEXTAUI_PRO_TOKEN.

  3. Añade el bloque

    pnpm dlx shadcn@latest add @hextaui-pro/models

Conéctalo a tu API

Coloca ModelSettings dentro de un SettingsSection. Pasa el catálogo y lo guardado, guarda en onSave y devuelve el catálogo más reciente desde onRefresh. Lanza un error desde cualquiera de los dos para mostrar el mensaje, y el borrador se conserva.

"use client"

import { IconCube } from "@tabler/icons-react"

import { SettingsSection, SettingsShell, type SettingsSectionItem } from "../settings/settings"
import { ModelSettings, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

const sections: SettingsSectionItem[] = [{ id: "models", label: "Models", icon: <IconCube /> }]

export function ModelsPage({
  models,
  values,
}: {
  models: ModelInfo[]
  values: ModelSettingsValues
}) {
  return (
    <SettingsShell sections={sections} className="h-svh">
      <SettingsSection id="models">
        <ModelSettings
          models={models}
          values={values}
          onSave={async (next) => {
            const response = await fetch("/api/settings/models", {
              method: "PUT",
              body: JSON.stringify(next),
            })
            if (!response.ok) throw new Error("Check your connection and try again.")
          }}
          onRefresh={async () => {
            const response = await fetch("/api/models")
            if (!response.ok) throw new Error("The model list is unavailable.")
            return (await response.json()) as ModelInfo[]
          }}
        />
      </SettingsSection>
    </SettingsShell>
  )
}

Probar servidores personalizados

onTestConnection recibe la URL base, el ID del modelo y la clave. Resuelve cuando el servidor responde, o lanza un error con un mensaje que la gente pueda atender. Add model ejecuta primero la misma prueba, para que un servidor roto nunca llegue a la lista.

"use client"

import { ModelSettings, type ModelConnection, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

async function testConnection({ baseUrl, model, apiKey }: ModelConnection) {
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
    },
    body: JSON.stringify({ model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }),
  }).catch(() => {
    throw new Error(`Couldn’t reach ${new URL(baseUrl).host}. Check the URL and that the server is running.`)
  })
  if (response.status === 401) throw new Error("The server said 401. Check the API key.")
  if (response.status === 404) throw new Error(`The server doesn’t know “${model}”.`)
  if (!response.ok) throw new Error(`The server said ${response.status}.`)
}

export function ModelsWithCustomServers({
  models,
  values,
  onSave,
}: {
  models: ModelInfo[]
  values: ModelSettingsValues
  onSave: (values: ModelSettingsValues) => Promise<void>
}) {
  return (
    <ModelSettings
      models={models}
      values={values}
      onSave={onSave}
      onTestConnection={testConnection}
    />
  )
}

Tus propios niveles de esfuerzo y tareas

efforts define los niveles del control deslizante, y el efforts de cada modelo enumera los que admite. tasks define las tareas en segundo plano que obtienen su propio modelo.

"use client"

import { ModelSettings, type ModelInfo, type ModelSettingsValues } from "@/components/blocks/models/model-settings"

const models: ModelInfo[] = [
  {
    id: "nova-3",
    name: "Nova 3",
    provider: "Hexta",
    context: 200_000,
    speed: "balanced",
    price: 2,
    efforts: ["none", "light", "deep"],
    recommendedEffort: "light",
  },
  {
    id: "nova-3-mini",
    name: "Nova 3 Mini",
    provider: "Hexta",
    context: 128_000,
    speed: "fast",
    price: 1,
    efforts: ["none", "light"],
  },
]

const efforts = [
  { value: "none", label: "None" },
  { value: "light", label: "Light" },
  { value: "deep", label: "Deep" },
]

const tasks = [
  { id: "titles", label: "Chat titles", description: "Names new chats from the first message." },
]

export function ModelsWithOwnLevels({
  values,
  onSave,
}: {
  values: ModelSettingsValues
  onSave: (values: ModelSettingsValues) => Promise<void>
}) {
  return (
    <ModelSettings models={models} values={values} onSave={onSave} efforts={efforts} tasks={tasks} />
  )
}

Anatomía

Las partes que compones, de fuera hacia dentro.

ParteDescripción
ModelSettingsLa sección Models completa: valores predeterminados, la lista del selector de modelos y task models. Colócala dentro de un SettingsSection.
Default modelUn menú de los modelos habilitados con sus estadísticas, y chips con el contexto, la velocidad y el coste del elegido.
Default effortEl control deslizante de esfuerzo de Prompt Input, limitado a los niveles que admite el modelo predeterminado.
Model pickerBúsqueda, filtros, un banner de actualización, un grupo Pinned y un grupo por proveedor, cada fila con un switch y un menú.
Add model dialogURL base, ID del modelo, nombre visible y clave de API de un servidor compatible con OpenAI, con una prueba de conexión.
Task modelsUn modelo por tarea en segundo plano, o Auto.

ModelSettings

Debe renderizarse dentro de SettingsShell, normalmente en un SettingsSection, porque guarda a través de la barra de guardado del shell.

PropTipoPredeterminado
modelsEl catálogo. { id, name, provider, context?, speed?, price?, vision?, efforts?, recommendedEffort?, status?, description? }. speed es "fast" | "balanced" | "thorough", price va de 1 a 4, efforts enumera los valores de esfuerzo que admite el modelo (omítelo para modelos que no razonan) y status es "new" | "preview".
ModelInfo[]–
valuesLo guardado: { defaultModel, effort, enabled, pinned, tasks, custom }. enabled y pinned son ids de modelo, pinned en el orden del selector. tasks asigna un id de tarea a un id de modelo o a "auto". custom contiene los servidores añadidos.
ModelSettingsValues–
onSaveGuarda el borrador. Lanza un error para mostrar el mensaje en la barra de guardado y conservar el borrador.
(values) => void | Promise<void>–
onRefreshObtiene el catálogo más reciente. Los modelos con ids que no ha visto reciben una insignia New y un banner. Lanza un error para mostrar el motivo con Try again. Omítelo para ocultar el botón de actualizar.
() => Promise<ModelInfo[]>–
onTestConnectionComprueba un servidor personalizado. Resuelve si responde y lanza un error con un mensaje si no. Omítelo para añadir modelos personalizados sin prueba.
(connection: { baseUrl, model, apiKey }) => Promise<void>–
effortsLos niveles de esfuerzo, del más rápido al más inteligente.
{ value, label }[]Low, Medium, High, Max
tasksTareas en segundo plano que obtienen su propio modelo. Pasa [] para ocultar el grupo.
{ id, label, description? }[]Explore subagent, Chat titles, Summaries
KeyAcción
EscapeEn la búsqueda, borra la consulta.
EnterEn una búsqueda sin coincidencias, abre Add model con la consulta como ID del modelo.
←→Se mueve entre filtros. En el control deslizante de esfuerzo, cambia el nivel, deteniéndose en lo que admite el modelo predeterminado.
SpaceActiva o desactiva el modelo enfocado.
Alt↑En el switch o menú de un modelo fijado, lo sube en el selector. Alt+↓ lo baja. El foco permanece en el mismo control.
⌘SGuarda, como el resto de Settings. Ctrl+S en Windows y Linux.
  • Cada proveedor y el grupo Pinned es una lista con el nombre de su encabezado, y cada fila se nombra con su modelo.
  • Los switches se etiquetan con el nombre del modelo y se describen con su contexto, coste y capacidades. El switch del modelo predeterminado está deshabilitado e indica por qué.
  • Una región live polite anuncia cuántos modelos coinciden con una búsqueda o filtro, los resultados de actualizar, los cambios masivos, los fijados, los movimientos y cuándo el modelo limita el esfuerzo.
  • Cuando un modelo fijado se mueve o una fila cambia de grupo, el foco lo sigue hasta el mismo control.
  • La escala de coste tiene un nombre en texto, como Low cost, así que los puntos nunca son la única señal.
  • Con movimiento reducido, el banner, el resaltado de fila y el control deslizante no se animan.

Construido con

Los componentes gratuitos de HextaUI con los que está hecho Models. Cada uno se instala por separado.

Código

4 archivos, añadidos a components/blocks/models.