Hermes Agent v0.21.5
Resumen
v0.21.5 — otro tag que existe para los consumidores posteriores. Publicada el 24 de septiembre de 2026. Desde la v0.21.4: 1.610 commits sin merge · 4.828 archivos modificados (+164.132 / −149.440) · 460 PR fusionados · 475 incidencias cerradas, medido en el commit f97608f178d1ffeca59860195ab7da295f7c8e5f.
El tag está ahí por el mismo motivo que la v0.21.4: las imágenes Docker, Hermes Cloud y los despliegues alojados se construyen desde el tag de release más reciente, así que las correcciones de esta ventana tienen que aterrizar en una versión estable antes de que los usuarios de la nube puedan recibirlas. El cuerpo del release lo dice sin rodeos: el texto completo y curado se aplaza a la v0.22.0, que documentará todo desde la v0.21.0 en adelante: destacados, áreas funcionales y créditos completos de contribuidores. Nada de esta ventana se queda fuera.
Hasta entonces, esta página deja constancia de para quién es el tag y de los cambios de la ventana que ya están corriendo en tu máquina.
Destacados
1. El escritorio recibe catálogos completos en francés, alemán y español, además de un ajuste de dirección del texto
El escritorio ahora incluye catálogos de interfaz completos en francés, alemán y español, listados en Ajustes → Apariencia → Idioma. Los tres catálogos traducen todas las claves de en.ts, incluidos todos los rótulos y descripciones de ajustes de defineFieldCopy y la rotación de introducción que solo se muestra en pantalla (intro-{fr,de,es}.ts). Se registran como superposiciones de defineLocale() igual que ja, ar y ru, así que una clave que se añada al inglés más tarde cae al inglés en lugar de romper el typecheck de todos los contribuidores. El backend ya incluye locales/{fr,de,es}.yaml; display.language: fr|de|es, junto con alias regionales como fr-CA, de-AT y es-419, ahora resuelven al catálogo correspondiente en lugar de caer al inglés. El francés usa vous, el alemán usa Sie y el español usa el imperativo neutro tú. Los nombres propios y los identificadores técnicos (Hermes, MCP, API, OAuth, IDs de modelo, variables de entorno, nombres de archivo) se quedan sin traducir. PRs #120829.
Junto a esto llega Apariencia → Visualización del chat → Dirección del texto, con tres opciones: Automática / De derecha a izquierda / De izquierda a derecha. Hasta ahora, cada bloque de prosa del chat y cada línea del compositor elegían su dirección base a partir de su primer carácter fuerte (UAX#9 plaintext), y eso no distingue un párrafo en árabe que abre con un nombre en latín de un párrafo en inglés que cita árabe. Automática es exactamente el comportamiento anterior: ningún atributo nuevo, ninguna clave de almacenamiento; elegir RTL o LTR aplica un único dir a la prosa del chat y a los dos compositores, incluida cada línea de un borrador de varias líneas. El código se queda en LTR (los bloques de código, el código inline y KaTeX siguen aislados) y el cromo de la aplicación (barra lateral, barra de herramientas, botones del compositor) no se voltea. Es solo presentación: no entran caracteres de control bidi en los borradores, en los mensajes enviados ni en el texto copiado. La preferencia la gestiona el renderer, no es una clave de config.yaml. PRs #120822.
2. Las entregas de webhook pueden espejarse en la session del chat de destino
Por defecto, una entrega es fire-and-forget: cada evento corre en su propia session, así que responder «¿o sea que ya salió?» en ese chat te devuelve un «¿a quién te refieres?». Ahora una ruta puede activarlo con mirror_to_session: true (o hermes webhook subscribe … --mirror-to-session), y tras un envío correcto el texto entregado se añade a la session del chat de destino como [Webhook delivery: <route>] más el mensaje, en forma de turno de usuario etiquetado y con autoridad de usuario: la misma ruta y la misma convención de rol que los briefs de cron continuables (gateway.mirror.mirror_to_session). Desactivado por defecto; solo un booleano true real lo activa. El espejo corre dentro de _profile_scope(profile), así que una ruta /p/<profile>/ escribe en el state.db de ese profile y nunca en el de otro. Es best-effort: nunca hace fallar la entrega, y se omite cuando el chat aún no tiene session de gateway. En una ruta deliver_only el texto espejado es el payload renderizado en bruto, así que actívalo solo para fuentes que te parezca bien tener en tu conversación. PRs #120825.
3. Bot Screen llega a las imágenes alojadas mediante los tags -desktop
Los despliegues alojados e inmutables ahora obtienen Bot Screen descargando un tag de imagen -desktop. La imagen publicada sale sin Xvnc/Xfce y no puede instalarlos en tiempo de ejecución (hermes sin privilegios, sin sudo, /opt/hermes sellado), así que la capa de la imagen es la única vía de entrega. :latest / :main / :v* son la imagen que ya conoces; :latest-desktop / :main-desktop / :v*-desktop añaden los paquetes y el Chromium con interfaz de Playwright. Un manifiesto por variante, de modo que un fallo de publicación del escritorio no puede saltarse el :latest de la imagen slim. Los contenedores no tienen logind, así que XDG_RUNTIME_DIR=/tmp/hermes-runtime se crea en el arranque con permisos 0700 y propietario hermes; el antiguo fallback $HOME/.cache acababa en el volumen compartido /opt/data, donde dos instancias se peleaban por un mismo bloqueo de display, y un directorio con otro propietario o que sea un symlink se rechaza en lugar de aplicarle un chown. PRs #120914; la documentación de la función es website/docs/user-guide/features/bot-screen.md.
4. Añade un modelo por slug desde cualquier selector de modelos
El menú de modelos del compositor, el diálogo de cambio de modelo, Ajustes → Modelo y la lista de edición de modelos ya pueden añadir un modelo por slug: una nueva fila al pie, Añadir modelo personalizado…, convierte el cuadro de búsqueda en un campo de slug, ofrece una fila por cada provider configurado mientras escribes, y el slug recordado se queda en la lista como una fila normal con su × para quitarlo. PRs #120693.
5. Las voces locales dejan de recargarse en cada activación
tts.keep_warm_seconds (por defecto 60) es nuevo: después de liberar el último lease, la descarga espera ese tiempo, y cualquier interruptor que vuelva a encender la voz dentro de la ventana lo cancela y reutiliza el modelo ya cargado. 0 descarga de inmediato. Esto importa sobre todo en las conversaciones de voz que solo usan la palabra de activación, que terminan justo después del calentamiento de ~2 s de Piper: la voz se desalojaba milisegundos después de cargarse, así que cada activación pagaba la recarga completa. PRs #121080.
6. El bucle de voz del escritorio empieza a leer tu configuración
Leer en voz alta ya no pronuncia marcadores en inglés como «code block omitted» o «link», y ya no se salta las tablas Markdown: los bloques de código y las URL se quedan en silencio, los tokens de enlace a archivos MEDIA: nunca llegan a la voz (la puntuación que sigue justo a un token inline sí se conserva), un dos puntos al final de línea que quedaba colgando porque se eliminó el bloque siguiente pasa a ser un punto, y las tablas leen su fila de cabecera («Item, Value, Notes.») saltándose las filas del cuerpo. PRs #120752. La parada hablada ahora lee voice.stop_phrases (por defecto ["stop"]): antes comparaba contra una lista fija en inglés, así que un usuario ruso que decía «отбой» como indicaba el aviso lo enviaba al agent como prompt; además, la locución completa tiene que ser igual a una frase, y [] desactiva la parada hablada. La reproducción con barge-in ya no usa un disparador fijo de 0.14, que quedaba por encima del nivel de voz de unos auriculares Bluetooth HFP mientras se reproduce una respuesta, y por eso hablar encima de la respuesta nunca la interrumpía; ahora usa el valor existente voice.barge_in_threshold_multiplier (por defecto 3.0). PRs #120751.
7. Los atajos de voz con teclas de función se pueden reasignar
El dictado puntual del compositor es ahora una acción de teclado composer.dictate sin asignar, separada de la conversación de voz, y reutiliza la ruta de captura canónica del escritorio para teclas F, Bloq Mayús, Suprimir, Espacio y combinaciones con modificadores. El campo obsoleto voice.record_key del escritorio se elimina, con la nota de que esa configuración sigue siendo solo para CLI/TUI. El arbitraje de Electron hace que una F12 asignada llegue al renderer mientras que una F12 sin asignar conserva el comportamiento de DevTools. PRs #120928. En la misma ventana se arreglaron los flujos con teclas de función en macOS: el parser de la TUI mantiene intactas las secuencias de terminal F1–F12 (incluidas las rutas del protocolo de teclas modificadas), y se añadió Ctrl+R como alternativa portátil a F7 para el dock de trabajo en vivo, tanto en la TUI como en la CLI clásica. PRs #120666.
8. Una tanda de fallos que solo aparecen en Windows localizado
Cuatro problemas independientes, todos solo de Windows:
- El crash del nombre de zona horaria. Windows devuelve los nombres de zona en la página de códigos ANSI (
Paris, Madrid (heure d'été)como bytes cp1252). CuandoLC_CTYPEes UTF-8, esos bytes se decodifican consurrogateescape, de modo quetzname()acaba conteniendo surrogates sueltos;datetime.strftimeinsertatzname()en el formato como UTF-8, así que%ZlanzaUnicodeEncodeErrordentro destrftime, antes de que exista ninguna cadena que la pasada_sanitize_surrogatesya existente pueda limpiar. El system prompt se reconstruye en cada inicio de conversación y en cada compactación, así que el fallo volvía una y otra vez. El nuevohermes_time.safe_strftime()es idéntico byte a byte astrftimeen locales sanos (se mantiene el invariante de la caché de prefijo) y, en caso contrario, decodifica los bytes con escape de surrogate a través de la página de códigos ANSI. PRs #120748. - Decodificación de procesos hijo en Windows chino. En Windows,
_readerthreaddesubprocess.communicate()decodifica la salida del proceso hijo consubprocess._text_encoding()—locale.getencoding(), cp936/GBK en Windows en chino — siempre que una captura pasetext=Truesinencoding=. Los procesos hijos en cuestión escriben UTF-8, así que cualquier byte ilegal en GBK lanzaUnicodeDecodeErroren ese hilo, y elthreading.excepthookdel proceso serve lo imprime como una línea[gateway-crash].hermes_cli/web_routers/files.py::_fs_git_branchera uno de ellos (sus kwargs están en un literal de diccionario, así que la regla por líneas detext=Truenunca los encontraba) y el escritorio lo consulta continuamente. PRs #120749. - Rutas absolutas de Windows.
C:\...\report.htmly las rutas UNC\\server\share\...no se reconocían como rutas (así que no aparecía ninguna etiqueta de artefacto) ni las dejaba tranquilas el fallback del renderer, que trataba como relativo todo lo que no empezara por/y lo unía al cwd, produciendo rutas como/repo/C:\...; después, el rótulo de vista previa interpretabaC:como esquema de URL. El nuevoisWindowsAbsolutePathacepta una letra de unidad con cualquiera de las dos barras y un prefijo UNC. PRs #121074. - La sonda de arranque en frío. En un arranque en frío de Windows, el backend local responde por HTTP y luego su bucle de eventos se queda bloqueado entre 12 y 28 s mientras el GIL está retenido importando los módulos de plataforma del gateway. La sonda WebSocket del arranque se rendía tras un presupuesto fijo de 10 s, marcaba un fallo de arranque, derribaba el proceso hijo y acababa en la cascada «Ignoring stale Hermes backend exit (1)». Un backend lanzado por esta aplicación ahora sigue esperando más allá de los 10 s base mientras el proceso hijo siga vivo, hasta un tope de 90 s: el mismo presupuesto que el paso de anuncio de puerto ya concede a un arranque en frío. La señal de progreso es la vitalidad del proceso, no la frescura de su salida, porque el bloqueo es silencioso. Los gateways remotos, el botón «Test remote» y el enganche al backend del host mantienen el presupuesto fijo de 10 s. PRs #120750.
Mejoras
- Toda la oleada del SDK de plugins del escritorio (API de borradores del compositor, slots de lista de sessions y de decoración de filas, preferencias de navegación de la barra lateral, etiquetas de las píldoras de modelo, puentes tipados de ajustes/skills/toolsets/profiles, una primitiva de embed en sandbox, un slot de ajustes de apariencia y un puente público de eventos para backends de plugins) aterrizó en esta ventana; su texto previsto también se aplaza.
- La página de Conectores sustituyó a la pestaña MCP, con «Conectar ahora» para los servidores MCP de un plugin recién instalado, y las herramientas y skills de los plugins instalados pasan a estar activas en todos los chats abiertos; el onboarding ofrece plugins del catálogo junto a los conectores.
- Kanban recibió una pasada de diseño: un modal de ticket a dos columnas y texto de tareas en markdown.
- La ventana también trae una larga serie de trabajo de rendimiento en rutas calientes: carga de configuración, registro de herramientas, manejo de mensajes del gateway y selector de modelos.
Actualización
hermes update # instalaciones por git
# o vuelve a ejecutar el instalador de una línea
Docker / Hermes Cloud: las imágenes se construyen desde este tag, nousresearch/hermes-agent:v2026.9.24.
Changelog completo: v2026.9.21…v2026.9.24
← Hermes Agent ChangelogCorrespondencia de versiones: el tag se basa en la fecha (
v2026.9.24) y la versión semántica esv0.21.5— el mismo release.