Modelos
Un modelo es la única capacidad que todo agente necesita y la única en la que nadie piensa como capacidad. Nombrar un proveedor es todo lo que es configurarlo.
Una lista, y casi solo un proveedor
models:
- id: deepseek-v4-flash # el id hace de modelo cuando ya lo es
provider: deepseek
- id: sonnet
provider: anthropic
model: claude-sonnet-4-6
defaults:
model: deepseek-v4-flash # donde empieza cada agente
Antes eran cuatro cosas acopladas — el proveedor, el modelo, una clave de relleno en el entorno del sandbox y una concesión que nombraba el host del proveedor — y cualquiera de ellas mal no es un error de arranque sino un turno que muere en el proxy, quejándose de algo que el operador nunca escribió. Dónde vive un proveedor, cómo se llama su clave y si la clave va en una cabecera bearer o en una propia son hechos sobre el proveedor y no decisiones que nadie pueda tomar, así que no se escriben.
Un proveedor que acá no conoce nadie funciona igual diciendo las dos cosas que habría dicho la tabla: un host y un keyEnv. La clave en sí nunca está en este archivo ni en el agente — keyEnv nombra una variable del entorno del propio plano de control, y la concesión que produce cada modelo es lo que la escribe en la petición al salir.
/model es una elección entre lo que existe
▸ /model flash deepseek/deepseek-v4-flash (this one) /model sonnet anthropic/claude-sonnet-4-6 /model gpt-5 openai/gpt-5 (no OPENAI_API_KEY) ╭──────────────────────────────────────────────────────────────────────╮ │ > /model │ ╰──────────────────────────────────────────────────────────────────────╯ ↑↓ model ⏎ choose ^C quit
Cada fila dice los dos hechos sobre un modelo que no son su nombre — de quién es y cómo lo llaman — más el que decide si el turno siguiente responde siquiera. Un modelo del que este plano no tiene clave se ofrece y se marca, no se esconde, porque está configurado y la mitad que falta es una clave que podés pegar dos paneles más allá. Al escribir se estrecha la lista contra el id, el proveedor y el nombre propio del proveedor a la vez, así que /model anthropic encuentra el que se llama sonnet.
Todos los modelos de esa lista ya son alcanzables por todos los agentes — configurar uno es lo que lo concedió — así que moverse entre ellos cambia lo que cuesta un turno y lo bueno que es, y no cambia nada de lo que el agente puede alcanzar. Eso es lo que lo hace un comando y no una edición y un reinicio, y es por lo que a un agente se le permite pedirlo.
No se recrea nada para hacerlo. El contenedor se arrancó con un relleno para cada proveedor que esto conoce, y el runner pregunta con qué pensar al principio de cada turno — así que un cambio aterriza en el turno siguiente, y un turno que ya está corriendo termina con el modelo que se le dio al empezar. Esa última parte se dice en voz alta, porque el cambio parece instantáneo y no lo es.
Las dos mitades son una lista en la pantalla de configuración
│ config │ │ │ │ holds from the next turn — nothing restarts. │ │ │ │ providers │ │ ● deepseek DEEPSEEK_API_KEY flash │ │ ○ anthropic ANTHROPIC_API_KEY sonnet │ │ ○ openai OPENAI_API_KEY gpt-5 │ │ ○ groq GROQ_API_KEY no models │ │ │ │ models │ │ ● flash deepseek from the file │ │ ○ sonnet anthropic from the file │ │ ○ gpt-5 openai added here │ │ + a model │ │ ╭────────────────────────────────────────────────────────────╮ │ │ │ ANTHROPIC_API_KEY no key, refused at the proxy │ │ │ ╰────────────────────────────────────────────────────────────╯ │
Un modelo son tres líneas de configuración y una variable exportada, y la variable es la mitad que no está en el archivo — así que es la mitad que se olvida. El fallo que eso produce es un plano que está corriendo y configurado y rechazado en el proxy, con turnos que mueren por un host que nadie escribió. ● es algo que este plano puede usar ahora mismo y ○ algo que no, la misma marca que usa la columna de agentes.
⏎ sobre una clave la toma, enmascarada mientras se escribe y nunca vuelta a mostrar. Va al plano por el mismo socket por el que va un shell, y por la misma razón: tener ese socket es lo que hace a alguien el operador, y una clave que llegara por webhook sería un desconocido pagando con tu cuenta. Una clave pegada acá rige desde el turno siguiente, sin nada reiniciado y nada redesplegado; una línea vacía la retira, y la pregunta vuelve a ir al entorno propio del plano.
+ a model pregunta a los proveedores en vez de preguntarte a vos
│ 3 on offer │ │ › gpt-5-mini openai │ │ gpt-4o-mini openai │ │ o4-mini openai │ │ ╭────────────────────────────────────────────────────────────╮ │ │ │ model openai mini │ │ │ ╰────────────────────────────────────────────────────────────╯ │
Que te tomen una clave y luego te pidan un nombre de modelo es que te pidan el único dato que la clave acaba de permitirle buscar al plano. Así que a cada proveedor del que tiene una clave se le pregunta a qué responde, todos a la vez, y lo que vuelve es una lista por la que moverse con las flechas. Al escribir se estrecha contra el proveedor y el id a la vez y en cualquier orden, así que openai mini llega sin recordar cuál de gpt-5-mini y gpt-5-nano era el bueno.
Un proveedor que no responda se nombra debajo de la lista en vez de contarse como que no tiene nada, ya que una lista vacía es la forma en la que llegan tanto una clave equivocada como un catálogo vacío. Escribir uno a mano sigue funcionando y tiene que hacerlo — tres palabras, un nombre, el proveedor con el que piensa y el nombre propio que el proveedor le da, así que sonnet anthropic claude-sonnet-4-6 se toma tal cual se escribió.
Lo que declaró el archivo está para leerse y no para cambiarse. from the file es una fila que esta pantalla no va a tapar y no va a soltar. Todo lo que se da acá vive en un almacén junto a config.yaml y nunca dentro, así que un redespliegue devuelve lo que se escribió ahí y lo que se escribió acá sobrevive al redespliegue por su cuenta. Esta es la única pantalla donde el teclado concede en vez de pagar, y es deliberado: llegar a ella significa tener el socket de control del plano, que es todo lo que es ser el operador acá.