Skip to content

docs: la seccion de agentes en los dos idiomas, y el CLI con instalador - #56

Merged
borjaperfra merged 5 commits into
mainfrom
docs/modelos-y-agent-setup
Sep 12, 2026
Merged

borjaperfra merged 5 commits into
mainfrom
docs/modelos-y-agent-setup

Conversation

@borjaperfra

Copy link
Copy Markdown
Contributor

Cierra el hueco que quedaba de la documentación: la sección "Configurar tu agente" existía solo en español, y el CLI seguía documentado como "clona el repo y compila con Go".

Qué entra

Las 16 páginas en inglés. Es lo que docsI18n.test.ts exigía: los dos idiomas tienen que tener el mismo conjunto de ficheros, el mismo order y la misma forma de grupos. Sin ellas, el selector de idioma del encabezado era un enlace a un 404 en cada una de esas páginas. Seis tests estaban en rojo por esto.

El catálogo único de model-ids (src/lib/modelCatalog.ts), con un test que impide que las superficies que escriben un id se separen. Ya habían divergido en las dos direcciones sin que fallara ninguna build: la tabla de la home publicaba el reranker como qwen3-reranker mientras la API responde a rerank.

/install deja de ser un 404. Sirve el scripts/install.sh de nan-cli, que es la línea que el README del CLI anuncia. No se copia el script aquí: se sirve el de allí, para que no haya dos copias que se separen.

La página del CLI, reescrita. nan-cli v0.1.1 ya publica binarios, así que lo que lleva es el curl | bash, con cómo comprobarlo, cómo actualizar, cómo desinstalar e INSTALL_DIR para no tocar /usr/local/bin. Compilar desde el código sigue documentado, plegado, porque es la única vía en Windows.

La página de OpenCode, con el esquema bueno. limit: { context, output } en vez de contextWindow, que no existe en el esquema de opencode (#8). Mismo arreglo que la #52 hace en la página de ejemplos, y con las mismas cifras medidas contra el proxy.

Dos decisiones que conviene mirar

/install apunta a la etiqueta v0.1.1, no a main. Lo que devuelve esa ruta se ejecuta en la máquina de un miembro, bajo sudo en la ruta por defecto. Desde una rama, cualquier push al repo del CLI cambia eso al instante y sin revisión por medio. No obliga a tocarlo en cada release, porque el script le pide a la API de GitHub la última versión en tiempo de ejecución: solo hay que subirlo cuando cambie el propio install.sh. Hay un test que exige que el ref sea una etiqueta.

La lista de grupos conocidos de DocsShell.test.ts gana "Set up your agent". Sigue cerrada a propósito: una errata en group no rompe ninguna build, solo abre en silencio una sección de nav con una sola página dentro.

Probado

  • npm test: 884 pasan, 0 fallan (venían 6 en rojo).
  • npm run build y astro check: limpios, 0 errores.
  • Las 22 páginas de docs responden 200 en los dos idiomas, y las dos barras laterales salen con las mismas cuatro secciones.
  • El instalador, de punta a punta desde Linux contra esta rama sirviendo /install: descarga, verifica el sha256 e instala un nan que responde v0.1.1.

Choca con la #52

Las dos tocan examples.md: esta rama saca de ahí los bloques de configuración de cliente (ahora viven en la página de cada herramienta) y la #52 los reescribe. Al mergear la segunda habrá que resolverlo a mano, y docsClientConfigs.test.ts tendrá que leer opencode.mdx en vez de examples.md. El contenido correcto es el de la #52; lo único que cambia es dónde vive.

🤖 Generated with Claude Code

borjaperfra and others added 5 commits September 12, 2026 12:53
Los ids de modelo se escribian a mano en cinco superficies sin relacion
entre si: la tabla de la home, las fichas de /docs/models, los snippets de
/docs/examples, la tabla de catalogo dentro del openapi y el quickstart.
Habian divergido en las dos direcciones y ningun build fallaba:

- La home publicaba el reranker como `qwen3-reranker` mientras la API
  responde a `rerank`. Quien copiaba ese id de la portada recibia un 404
  `model_not_found`.
- `flux-2-klein` estaba servido por la API y ausente de la tabla, que es la
  forma de tener un modelo invisible.

modelCatalog.ts recoge los hechos que un lector necesita para ELEGIR (para
que sirve, cuanto contexto, que acepta, que gasta), no la prosa editorial de
cada ficha. Las fichas siguen escritas a mano, porque lo que dicen de un
modelo es un juicio. Lo que no puede ser un juicio es como se escribe un id.

modelCatalog.test.ts compara ese catalogo contra la home, las fichas de los
dos idiomas, los snippets de las guias y la tabla del openapi. Revisar una
tabla de ids a ojo no coge ninguno de los dos fallos de arriba; esto si.

La ventana y la cuota de glm5.3 NO se repiten aqui: ya viven en
rateLimits.ts, que lee del entorno y alimenta la ficha y /api/docs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El README de helmcode/nan-cli lleva desde siempre diciendo que el CLI se
instala con `curl -fsSL https://nan.builders/install | bash`, y esta web
respondia 404. Un miembro se topo exactamente con eso, acabo clonando el
repo y compilandolo con Go, y solo llego despues de un rodeo largo. El
instalador es lo primero que toca alguien que entra, asi que un 404 ahi
cuesta mas de lo que parece.

El script no se copia a este repo: vive junto al codigo que instala
(scripts/install.sh en nan-cli), y una segunda copia aqui se quedaria vieja
la primera vez que el CLI cambie como se despliega. Esta ruta busca aquel y
lo sirve.

Se sirve en vez de redirigir porque el sentido de todo esto es un comando
que entra en un shell: una redireccion solo funciona si quien llama pasa
`-L`, y un 302 con cuerpo vacio metido en bash es un no-op silencioso, que
es peor que un error. Por lo mismo, los fallos se devuelven como un script
que escribe el motivo y sale con codigo 1, y no como una pagina de error.

Queda pendiente en el otro repo lo que hace falta para que esto sirva de
algo: nan-cli no tiene ninguna release publicada, asi que el script no
encuentra binarios que descargar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cuatro piezas para que las guias se puedan escanear y no solo leer:

- AgentGrid sustituye a una tabla de herramientas. Una tabla es la forma
  correcta de comparar numeros y la incorrecta para elegir: quien llega ya
  sabe que herramienta usa y lo que quiere es encontrarla, que es reconocer,
  no leer. Las marcas y las tarjetas se barren de una pasada.
- AgentLogo resuelve esas marcas desde simple-icons, con importaciones
  nombradas una a una y nunca `import * as`, que anularia el tree-shaking y
  meteria varios miles de iconos en un Worker que tiene limite de tamano.
  Codex viene de lobehub/lobe-icons (MIT), porque simple-icons ya no publica
  la familia de OpenAI. Lo que no tiene marca cae a un monograma.
- Steps numera con un contador de CSS y no con el texto. Escritos a mano,
  los numeros se quedan viejos la primera vez que alguien mete un paso en
  medio, y un paso "4" justo detras del 4 es de los errores que nadie avisa.
- Details colapsa lo que es cierto pero no hace falta en la primera lectura.
  Elemento nativo: se imprime, lo encuentra el buscador del navegador,
  funciona sin JavaScript y un lector de pantalla anuncia su estado.

Dos marcas disponibles quedan fuera a proposito y esta escrito en el
codigo, porque son otra empresa con el mismo nombre: el "Hermes" del
paquete es myhermes.de, una empresa de paqueteria alemana, y el unico
"OpenAI" es OpenAI Gym. Un logo equivocado es peor que ninguno.

Todos se registran en mdxToText con su version en texto plano, que es el
contrato de /api/docs: un componente sin extractor tira la ruta entera de
esa pagina en vez de degradar. Los tres traen fixture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ntes

La documentacion tenia el contenido que decide si alguien se queda o se va
en el sitio equivocado. Esta es la mitad en castellano; el ingles va aparte.

Lo que faltaba:

- Nada respondia a "que modelo pido". Habia doce ids y cero criterio.
  "Elige tu modelo" es una tabla de decision por tarea, la lista plana de
  ids, como se leen, que significa cada tipo de cuota, y GET /v1/models
  destacado, que es la respuesta que no se queda vieja.
- El unico bloque de codigo del quickstart no era JSON valido ni el
  contenido de ningun fichero real, y en 39 lineas no habia forma de
  comprobar que la clave funciona ni que hacer cuando falla.
- Las configuraciones de herramientas estaban en la linea 634 de 643 de
  "Ejemplos", detras de los snippets de whisper y kokoro, y cubrian cuatro
  herramientas. Ahora son una seccion con una pagina por herramienta, todas
  con la misma forma: requisitos, configuracion con la ruta del fichero,
  como comprobarlo y problemas conocidos.

Lo que cambia de fondo:

- Claude Code no se conecta directo y la documentacion no lo decia. Habla el
  formato de Anthropic y el cluster el de OpenAI. Su pagina explica los dos
  caminos que existen, empezando por delegar en OpenCode, que es el que no
  monta infraestructura y esta probado contra el cluster.
- El CLI de NaN no se mencionaba en ningun sitio, y configura solo OpenCode,
  Codex, Pi y droid. Tiene pagina, y avisa de que `nan auth login` apunta a
  un endpoint retirado.
- Gentle-AI entra como lo que recomendamos configurar encima, una vez
  conectado el agente. No es una forma de conectarse y la pagina lo dice
  desde el primer parrafo.
- El id de ejemplo deja de ser `qwen3.6`, que es la generacion anterior, y
  pasa a ser `deepseek-v4-flash`.

El orden de las paginas es contiguo desde cero porque DocsShell.test.ts lo
exige, asi que insertar la seccion movio a las demas, apiDoc.ts incluido.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…linea

Las 16 paginas que se escribieron en espanol existen ya en ingles, que es
lo que los tests de docsI18n exigian: los dos idiomas tienen que tener el
mismo conjunto de ficheros, el mismo order y la misma forma de grupos, o
el selector de idioma del encabezado lleva a un 404.

Entra ademas la seccion "Set up your agent" en la lista de grupos
conocidos de DocsShell.test.ts. Esa lista esta cerrada a proposito: una
errata en `group` no rompe ninguna build, solo abre en silencio una
cuarta seccion de nav con una sola pagina dentro.

La pagina del CLI ya no manda clonar el repo y compilar con Go. nan-cli
v0.1.1 publica binarios, asi que lo que lleva es el `curl | bash` que el
README anunciaba desde el principio, con su comprobacion, como se
actualiza, como se desinstala y `INSTALL_DIR` para no tocar
/usr/local/bin. Compilar sigue documentado, plegado, porque es la unica
via en Windows. En los dos idiomas.

Y /install pasa a servir el script desde la etiqueta v0.1.1 en vez de
main. Lo que devuelve esa ruta se ejecuta en la maquina de un miembro,
bajo sudo en la ruta por defecto: desde una rama, cualquier push lo
cambia sin revision por medio. No obliga a tocar esto en cada release,
porque el script pide a GitHub la ultima version en tiempo de ejecucion;
solo cuando cambie el propio install.sh. Hay un test que lo exige.

La pagina de OpenCode se publica ya con `limit: { context, output }` en
los dos idiomas, en vez del `contextWindow` que no existe en el esquema
de opencode (#8). Las cifras son las medidas contra el proxy,
las mismas que lleva la pagina de ejemplos en la PR #52.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@borjaperfra
borjaperfra merged commit 417e3fe into main Sep 12, 2026
2 checks passed
@borjaperfra
borjaperfra deleted the docs/modelos-y-agent-setup branch September 12, 2026 10:57
borjaperfra added a commit that referenced this pull request Sep 12, 2026
… vive

Recupera la #52 sobre main, despues de que la #56 moviera los bloques de
configuracion de `examples.md` a la pagina de cada herramienta. El
contenido es el de la #52; lo que cambia es donde vive y quien lo mira.

El fallo de fondo (#8) era doble y silencioso. La ventana de contexto se
publicaba como `contextWindow`, que no es una propiedad de
https://opencode.ai/config.json: `limit: { context, output }` si lo es, y
los dos subcampos son obligatorios. Una clave desconocida no da ningun
error que un miembro vea, opencode se queda con su propia suposicion, y
el sintoma es que compacta demasiado pronto en los modelos de contexto
largo. Y la lista decia "los 4 modelos LLM disponibles" mientras el
cluster sirve siete.

Las paginas de OpenCode y de VS Code publican ya los siete, con las
ventanas medidas contra el proxy el 2026-09-11 y con las cifras que
declara cada deployment.

En el bloque de VS Code, ademas, entrada y salida se reparten la ventana.
VS Code SUMA `maxInputTokens` y `maxOutputTokens` y trata el resultado
como el contexto del modelo, asi que publicar la ventana entera como
entrada con un presupuesto de salida encima le hacia creer que el modelo
aguanta un 25% mas: enseñaba el consumo contra ese numero y dejaba crecer
la conversacion hasta que el proxy devolvia un error de longitud a mitad
de sesion.

El test valida contra el esquema real de opencode, no contra una lista de
nombres: la lista solo veia las claves de primer nivel y dejo pasar cinco
violaciones en la revision de la #52. El esquema va vendorizado para que
la suite no dependa de la red.

Dos cosas que cambian respecto de la #52:

- **El 401 del tier premium no se afirma.** La #52 exigia que la pagina
  dijera 401, citando una medicion de otro repositorio. Todo lo que
  publica este repo dice 403 `tier_restricted`: `openapi.json` en tres
  sitios, que es lo que sirven /docs/api y el bot de Discord, y la nota
  de /docs/choose-a-model. Una de las dos es falsa y esta suite no puede
  saber cual, asi que queda escrito como pregunta abierta en vez de
  congelar la contradiccion.
- **El escaneo de credenciales lee todas las paginas**, no una. Los
  bloques estan repartidos ahora, y un escaner que cubre la pagina donde
  menos probable es pegar una clave no vale gran cosa.

`examples.md` en ingles se pone a la par de la española, que es donde
estaba el conflicto: pierde los bloques que se mudaron y su ejemplo de
cabecera pasa de `qwen3.6` a `deepseek-v4-flash`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
barckcode added a commit that referenced this pull request Sep 12, 2026
…that replaced them

Re-scoped after #56 landed. That PR gave each tool its own page and wrote
configs that are already right — `limit: {context, output}`, the real
windows, the full endpoint URL. Reintroducing this branch's versions would
have been duplicated work, so it is dropped. Three things remain, and the
first two are live defects.

1. THE ENGLISH `examples.md` STILL CARRIED THE PRE-#8 BLOCK. #56 removed the
   IDE configs from the Spanish page and pointed it at /docs/agent-setup, and
   left the English one untouched: `contextWindow` (which opencode does not
   read), "the 4 available LLM models", deepseek-v4-flash at 500000. An
   English reader had two pages, `opencode.mdx` correct and `examples.md`
   stale, with the stale one sorting first under Guides. Mirrored the Spanish
   change: 176 lines removed, same closing pointer, and the two files are now
   the same length.

2. `qwen3.8-flash` EXCEEDED ITS WINDOW IN `vscode.mdx`, BOTH LOCALES. VS Code
   adds `maxInputTokens` and `maxOutputTokens` and treats the sum as the
   window; 240,000 + 32,000 = 272,000 against 262,144 overshoots by 9,856. The
   page's own reasoning was right — "maxInputTokens sits below the real
   context on purpose... there is no room left for the answer" — and only the
   arithmetic was wrong, which is exactly the case a test catches and a
   careful reader does not. 240,000 -> 220,000, leaving the same kind of
   margin the other two models have.

3. `docs-es/opencode.mdx` WAS COMMITTED WITH CRLF, the only such file in the
   repo. Nothing rendered wrong, but every JSON block in it was invisible to
   an exact-match parser: the first run of this suite found zero blocks there
   and would have "passed" the file by never reading it. Normalised, and the
   block finder now tolerates `\r` so a future stray file cannot silently
   disable the suite.

The suite validates what #56 wrote and nothing about model choice: these
pages publish CURATED subsets on purpose (vscode.mdx picks three and says
why), so it asserts that nothing published is missing from the catalogue —
not that everything in the catalogue is published.

Gates, each proven by mutation:

  input+output over the window        -> 2 failed
  contextWindow restored              -> 4 failed
  a model absent from the catalogue   -> 3 failed
  apiKey renamed to api_key           -> 1 failed
  a realistic key on any docs page    -> 1 failed
  the duplicate block returning       -> 1 failed

opencode blocks are validated against the vendored schema with ajv rather
than a list of property names, which sees no types, enums or nesting. ajv is
now a declared devDependency; it was imported transitively before, which
`npm ci` would have broken.

Full suite 910 passed, `npm run build` clean, `npm ci` clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
borjaperfra added a commit that referenced this pull request Sep 12, 2026
* fix(docs): una config de opencode que opencode sabe leer, donde ahora vive

Recupera la #52 sobre main, despues de que la #56 moviera los bloques de
configuracion de `examples.md` a la pagina de cada herramienta. El
contenido es el de la #52; lo que cambia es donde vive y quien lo mira.

El fallo de fondo (#8) era doble y silencioso. La ventana de contexto se
publicaba como `contextWindow`, que no es una propiedad de
https://opencode.ai/config.json: `limit: { context, output }` si lo es, y
los dos subcampos son obligatorios. Una clave desconocida no da ningun
error que un miembro vea, opencode se queda con su propia suposicion, y
el sintoma es que compacta demasiado pronto en los modelos de contexto
largo. Y la lista decia "los 4 modelos LLM disponibles" mientras el
cluster sirve siete.

Las paginas de OpenCode y de VS Code publican ya los siete, con las
ventanas medidas contra el proxy el 2026-09-11 y con las cifras que
declara cada deployment.

En el bloque de VS Code, ademas, entrada y salida se reparten la ventana.
VS Code SUMA `maxInputTokens` y `maxOutputTokens` y trata el resultado
como el contexto del modelo, asi que publicar la ventana entera como
entrada con un presupuesto de salida encima le hacia creer que el modelo
aguanta un 25% mas: enseñaba el consumo contra ese numero y dejaba crecer
la conversacion hasta que el proxy devolvia un error de longitud a mitad
de sesion.

El test valida contra el esquema real de opencode, no contra una lista de
nombres: la lista solo veia las claves de primer nivel y dejo pasar cinco
violaciones en la revision de la #52. El esquema va vendorizado para que
la suite no dependa de la red.

Dos cosas que cambian respecto de la #52:

- **El 401 del tier premium no se afirma.** La #52 exigia que la pagina
  dijera 401, citando una medicion de otro repositorio. Todo lo que
  publica este repo dice 403 `tier_restricted`: `openapi.json` en tres
  sitios, que es lo que sirven /docs/api y el bot de Discord, y la nota
  de /docs/choose-a-model. Una de las dos es falsa y esta suite no puede
  saber cual, asi que queda escrito como pregunta abierta en vez de
  congelar la contradiccion.
- **El escaneo de credenciales lee todas las paginas**, no una. Los
  bloques estan repartidos ahora, y un escaner que cubre la pagina donde
  menos probable es pegar una clave no vale gran cosa.

`examples.md` en ingles se pone a la par de la española, que es donde
estaba el conflicto: pierde los bloques que se mudaron y su ejemplo de
cabecera pasa de `qwen3.6` a `deepseek-v4-flash`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): el tier premium responde 401, medido, no el 403 que publicabamos

Una clave de la comunidad normal pidiendo `glm5.3`, medido el 2026-09-12
contra api.nan.builders:

  HTTP 401
  {"error":{"message":"This API key does not have access to the requested
   model.","type":"auth_error","param":"None","code":"401"}}

Y `GET /v1/models` no le lista `glm5.3` siquiera. La misma clave contesto
200 con deepseek-v4-flash en el mismo minuto, asi que era el tier y no la
credencial.

El sitio publicaba `403 tier_restricted` en las cuatro superficies que
mencionan el caso: `openapi.json` en tres sitios, que es lo que sirven
/docs/api y el bot de Discord, la nota de /docs/choose-a-model y la tabla
de errores del quickstart. Importa porque un 401 se lee como clave rota:
la pagina mandaba a rotar una credencial que esta bien.

El `403 tier_restricted` no desaparece: sigue documentado para un
ENDPOINT que un tier no alcanza, que es el caso de la generacion de
imagenes. Lo que se corrige es el caso por modelo, que es el que estaba
medido al reves.

Esto zanja lo que la #52 pedia y esta rama habia dejado como pregunta
abierta. Ahora que hay medicion reproducible, se afirma en un test, con
la respuesta citada entera para que el dia que cambie se vea contra que
se escribio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: borjaperfra <borjaperfra@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
borjaperfra added a commit that referenced this pull request Sep 13, 2026
…ido (#58)

* fix(docs): dos snippets que fallaban en la maquina del lector

El de embeddings acababa en `print(len(embeddings[0]))  // 4096`, copiado del
bloque de JavaScript de al lado. En Python `//` es division entera, no un
comentario: la linea imprime, evalua `None // 4096` y revienta con TypeError.
No es un error de sintaxis, asi que ningun parser lo ve; solo lo ve quien lo
ejecuta.

El de Whisper en Node importaba `form-data`, construia el FormData, le hacia
append del fichero y no lo usaba nunca: el SDK de OpenAI recibe el stream
directamente. La pagina solo dice `npm install openai`, asi que el snippet
fallaba en la linea del import a quien lo pegaba tal cual.

docsSnippets.test.ts deja las dos reglas. La primera mira la FORMA, no la
semantica, porque no hay otra cosa que mirar: `len(x) // 2` es Python legitimo
y sigue permitido, y lo que distinguia al bug eran los dos espacios con los que
se alinea un comentario, que es justo lo que viaja cuando alguien copia una
linea del bloque de al lado. La segunda compara lo que un snippet importa con
lo que la pagina manda instalar, que es el contrato que el lector tiene con
ella.

Verificado reintroduciendo los dos fallos: el test los coge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(examples): el ejemplo de imagen que la pagina prometia y no tenia

/docs/choose-a-model dice de esta pagina, por su nombre, que trae "una llamada
completa para cada tipo de modelo". Era falso: `flux-2-klein` llevaba semanas
servido y no habia ningun ejemplo de imagen en ninguno de los dos idiomas, asi
que la unica forma de saber como se llama a /images/generations era la
referencia de la API.

La seccion cubre generacion (curl y python) y edicion imagen a imagen (node),
con lo que de verdad se equivoca uno al escribirlo a mano: los lados de `size`
divisibles entre 16 y entre 256 y 1536, `n` hasta 4, el enlace que caduca en
una hora, `b64_json` como alternativa, y `seed`/`guidance` por `extra_body`
porque son extensiones de NaN y el SDK de OpenAI no las conoce. Los parametros
salen del openapi.json de este repo, que es la fuente que la propia web sirve.

El test nuevo compara las secciones de la pagina contra modelos.json y exige
una por familia de endpoint. Por familia y no por modelo, porque eso es lo que
la pagina es: los siete LLM comparten /chat/completions y basta uno. Lo que
tiene endpoint propio -- embeddings, rerank, kokoro, whisper, flux -- no lo
puede representar ningun otro.

Verificado en las dos direcciones: quitar la seccion falla, y escribir mal el
id tambien.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): la misma ventana, se escriba donde se escriba

Tres sitios publicaban el mismo numero de tres maneras y ninguno miraba a los
otros:

- La ficha de gemma4 y la de qwen3.6 decian "256K tokens" y el bloque de
  opencode dice 262144. Es la misma ventana en dos convenciones, binaria en la
  ficha y decimal en la config, y desde fuera eso no se distingue de una cifra
  vieja. La convencion de esta web es la de formatTokens -- decimal, hacia
  abajo, nunca de mas -- asi que la ficha pasa a 262K, y con ella la tabla de
  la home.
- Las "incidencias conocidas" de OpenCode decian que sus ventanas son "las
  mismas cifras que publica Ejemplos". Desde la #56 Ejemplos no publica
  ninguna: los bloques se fueron a la pagina de cada herramienta. Ahora apunta
  a donde viven de verdad, el bloque de VS Code y las fichas de /docs/models.

El test compara la ficha contra formatTokens(ventana), no contra un segundo
literal, que es lo que hace que cambiar la convencion mueva las dos a la vez.
Y hace lo mismo con el campo `specs` de modelos.json, que es prosa libre y el
unico sitio donde una cifra puede moverse sin que ningun consumidor se entere.

De paso, un comentario duplicado que habia quedado de la #52 describiendo el
mismo test dos veces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): qwen3.6 deja de ser el modelo por defecto donde aun lo era

/docs/choose-a-model lo llama "generacion anterior" y dice que no es por donde
empezar hoy; /docs/models seguia presentandolo como "el modelo insignia" y la
referencia de la API lo ponia delante de todo el que llega: el quickstart del
overview, el `example` del campo `model`, el ejemplo de peticion, el de
respuesta y los tres code samples. La referencia es la pagina que se lee con
la API ya delante, asi que es la copia que mas se pega, y apuntaba justo al
modelo del que el resto de la doc te aparta.

Pasan a `deepseek-v4-flash`. Dos ejemplos se quedan donde estaban, y por un
motivo, no por inercia: `json_schema` necesita un modelo con salida
estructurada, que segun el propio esquema son qwen3.6 y gemma4, y
`premium_tier` es un ejemplo sobre el tier premium. La ficha de qwen3.6 dice
ahora lo mismo que choose-a-model: sigue respondiendo para no romper
configuraciones, pero hoy se empieza por otro.

El test lee el modelo recomendado de la tabla del quickstart en vez de
repetirlo aqui, asi que el dia que esa recomendacion cambie falla hasta que la
referencia la siga. Y comprueba que el ejemplo de salida estructurada sigue
sobre un modelo que el esquema declara compatible, que es la unica razon por
la que se le permite ser distinto.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): dos frases de la portada que la propia doc desmiente

"Si algo acepta una base URL y una API key, funciona con NaN", decian la
introduccion y el quickstart, y el quickstart ademas metia a Claude Code en la
lista de herramientas que se configuran con esos dos datos. La pagina de Claude
Code explica justo lo contrario y con razon: habla el protocolo de Anthropic, y
apuntar ANTHROPIC_BASE_URL al endpoint de NaN no funciona. Quien empieza por la
introduccion se entera de la excepcion despues de intentarlo. Ahora la
excepcion se nombra donde se hace la promesa.

"Los limites van por API key, no por modelo" era directamente falso mientras se
publicaba, en los dos idiomas: rateLimits.ts publica dos tablas por modelo y las
fichas de /docs/models llevan una fila RPM en qwen3-embedding, kokoro y whisper.
Quien planifica un lote contra "el limite es 60 rpm de tu key" se choca con el
techo de rerank o con el de whisper, que es mucho mas bajo, sin nada en la frase
que lo prepare.

El test es condicional sobre la config, no una lista de frases prohibidas para
siempre: el dia que las tablas por modelo se vacien de verdad, la frase vuelve a
ser cierta y el test deja de objetar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): cuando vuelve una cuota gastada depende del modelo

El quickstart contestaba al 402 con una sola frase para todos los modelos --
"el contador vuelve a cero cuando empieza tu periodo de facturacion" -- que es
cierta para uno de doce. /docs/choose-a-model ya lo tenia bien: `/mes` vuelve a
cero con el mes natural y solo `glm5.3` va por el periodo de Stripe, que casi
nunca es el dia 1. La diferencia entre las dos puede ser un mes de espera, y es
la frase que uno lee justo cuando esta bloqueado y decidiendo si esperar.

Lo mismo en la tabla de errores del quickstart y en la referencia de la API, que
ademas atribuia el 402 al periodo de facturacion en el texto general y no solo
donde toca.

El test es relacional: si la pagina de catalogo publica dos clases de periodo en
su columna de cuota, la pagina que explica el error tiene que nombrar las dos.
El dia que solo quede una, deja de exigirlo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(docs): la fila del 402 tiene que nombrar los dos periodos

El commit anterior dejo el test de glm5.3 fijado a la frase antigua, que era
justo la imprecisa. La intencion de esa asercion era otra -- que el 402 hable
de una asignacion de tokens y no del credito prepago de helmcode -- y esa se
mantiene; lo que cambia es que ahora exige ademas que la fila nombre el mes
natural y el periodo de facturacion de glm5.3, en vez de pinchar la version que
solo valia para un modelo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(i18n): el idioma que se colaba en la superficie del otro

Dos ficheros se sirven a los dos idiomas y ninguno de los dos estaba traducido
del todo.

modelos.json se renderiza en / y en /es. La cuota pasa por una funcion y sale
en el idioma que toca; `specs` no pasa por nada, asi que lo que este escrito
ahi es lo que ven las dos paginas. Decia "67 voces" en la home inglesa, al lado
de otras once filas en ingles, desde que existe la fila de Kokoro.

openapi.json es uno solo y lo renderiza Scalar en /docs/api y en /es/docs/api,
con la prosa en ingles. Los ejemplos no: el quickstart preguntaba "Hola", el
modelo contestaba "¡Hola! ¿En qué puedo ayudarte?", el de razonamiento decia
"Resuelve paso a paso" y los de imagen pedian "Un faro al atardecer sobre
acantilados". A quien no lee espanol le queda una pagina en ingles con las
cargas en espanol, que parece un error de copiar y pegar aunque todo lo demas
este bien.

Dos cadenas se quedan en espanol a proposito y el test las permite por nombre:
el ejemplo de embeddings empareja "Hola mundo" con "Hello world", que es
justamente lo que demuestra, y la respuesta de Whisper es la transcripcion de
un audio en espanol, que es contenido y no prosa.

La traduccion de la cuota estaba escrita a mano dentro de Models.astro, donde
ningun test podia mirarla: pasa a modelCatalog.ts como homeQuotaLabel. El test
de la tabla premium comprobaba el codigo fuente del componente y ahora
comprueba lo que sale, que es lo que importaba.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): Pi y OpenClaw publicaban una ventana redondeada a mano

"contextWindow": 1000000 para modelos que se sirven a 1.048.576 y a 1.048.575.
Un numero mas redondo, que parece deliberado, se queda un 4,6% corto y no
coincide con lo que esta misma web declara dos paginas mas alla. Quedarse corto
es la direccion inofensiva, pero quien compare dos de nuestras paginas no puede
saber cual de las dos se cree, que es justo lo que este fichero de tests existe
para evitar.

Solo se revisaban los bloques de OpenCode y de VS Code, porque eran los dos en
los que vivio el fallo de la #52. La regla nueva va sobre el CAMPO y no sobre
la pagina: cualquier bloque JSON de cualquier guia que declare un
`contextWindow` al lado de un id de modelo tiene que declarar el medido. Una
pagina de herramienta que se anada manana queda cubierta sin tocar esto.

Lo que NO toco, porque no lo se: el presupuesto de salida. opencode publica
32768 para glm5.3-flash, OpenClaw 65536 y Pi 16384. En cada herramienta ese
campo significa una cosa distinta -- tope del modelo, presupuesto por turno,
techo por peticion -- asi que no es evidente que tengan que coincidir, pero dos
de ellos dicen ser "lo maximo que acepta el modelo" y no pueden ser los dos.
Hace falta el dato de upstream para decidirlo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(copy): el plan decia "sin limite de tokens" encima de un limite de tokens

En la misma lista del plan de 70 EUR, la primera linea decia "Modelos
abiertos, sin limite de tokens" y la segunda "DeepSeek V4-Flash... 3B tokens al
mes". La FAQ de mas abajo lo explica bien -- sin contador en los modelos del
cluster, y cuota publicada en los frontier -- pero para entonces el lector ya
ha leido las dos lineas seguidas.

Lo que de verdad no tiene contador es la factura: la suscripcion es fija y no
se paga por token. Eso es lo que dicen ahora la entrada del plan, el cuerpo del
hero y el lead de "Que es NaN", y coincide con la respuesta de la FAQ y con la
columna de cuotas de /docs/choose-a-model, donde los cinco modelos con contador
son exactamente los cinco marcados como frontier.

No toco el eslogan ("Don't run out of tokens. Ever.") ni las dos citas
personales: un eslogan promete un tono, no una cifra, y una cita es de quien la
dice. Si quieres que tambien se muevan, se mueven.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docs): el techo de respuesta tambien es un numero, y eran tres

opencode publicaba 32768 para glm5.3-flash, el bloque de OpenClaw 65536 y el de
Pi 16384. Y dos de las tres frases que lo acompanan llamaban a su propia cifra
"el maximo que admite el modelo", que no pueden ser las dos. Cada herramienta
llama al campo de una manera -- `limit.output`, `maxTokens` -- y las tres
contestan a la misma pregunta: cuanto puede volver en una respuesta.

Un presupuesto por turno es otra cosa y se queda como esta: es una
recomendacion, no un limite, y OpenClaw lo escribe en `agents.defaults`, lejos
de ningun id de modelo.

La cifra en si sigue sin verificarse contra el proxy, y hay un numero publico
que no coincide: models.dev lleva a NaN como proveedor desde el 2026-09-03 y
cada modelo declara un `base_model`, asi que hereda el techo que publica el
MODELO y no el que acepta nuestro deployment -- 384000 en deepseek-v4-flash,
131072 en los flash de GLM y Qwen. gemma4 va al reves: 32768 alli y 65536 aqui,
que es la direccion que duele, porque promete mas de lo que el modelo emite.

Eso se mide con una peticion por modelo. Mientras tanto, las guias contestan
todas lo mismo, que es lo que fija el test nuevo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(limits): medido contra el proxy que techo de salida acepta cada modelo

Bisecando `max_tokens` hasta el 400 (que solo dice "Invalid request", asi que
hay que acorralar el numero), el 2026-09-13:

  deepseek-v4-flash  1048575     glm5.3-flash  1048575
  qwen3.8-flash       131072     mimo-v2.5      131072
  gemma4              262130     qwen3.6        262131

Dos conclusiones, y por eso las cifras publicadas se quedan donde estan.

En la mayoria no hay techo que publicar: gemma4 y qwen3.6 se quedan a 13 y 14
tokens de su ventana de 262144, que es la ventana menos el prompt. Es vLLM
acotando la respuesta sin limite aparte, que es justo lo que decia el comentario
de este fichero. Asi que 32768 y 65536 son un PRESUPUESTO que recomendamos, no
un limite que nadie impone.

Dos modelos si tienen techo de verdad: qwen3.8-flash y mimo-v2.5 rechazan por
encima de 131072, muy por debajo de su ventana, porque lo impone el upstream que
los sirve. Esa cifra es un hecho del endpoint, y es la que models.dev ya publica
para ellos.

Y una correccion a lo que escribi ayer: dije que gemma4 prometia mas de lo que
el modelo emite, porque models.dev declara 32768. No es asi -- eso es la ficha
de Google, y nuestro proxy acepta 262130. models.dev describe los MODELOS, no
este endpoint, y se equivoca en las dos direcciones.

De paso, el ejemplo de flux-2-klein que anadi ayer a /docs/examples, escrito
contra el openapi sin poder probarlo: lanzado tal cual contra la API devuelve
200 y `data[0].url`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(models): publicar el techo de respuesta de los dos modelos que lo tienen

De la medicion de ayer: qwen3.8-flash y mimo-v2.5 rechazan cualquier
`max_tokens` por encima de 131.072, muy por debajo de su ventana, porque lo
impone el upstream que los sirve. En los demas no hay techo que publicar -- el
proxy acepta hasta la ventana menos el prompt -- asi que solo estas dos fichas
ganan la fila.

Es el numero que le falta a quien se choca con un 400 y no entiende por que:
tiene 262K o 1M de contexto y la peticion se le cae igual.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: borjaperfra <borjaperfra@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@crstian19 crstian19 mentioned this pull request Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants