Files
nas-runbooks/common/accents-fleetwide-utf8-fix-20260828.md

61 lines
4.1 KiB
Markdown

# Accents disparaissant en ASCII — bug fleet-wide sur les 5 conteneurs Hermes
**Instance auteur** : hermes-nyora
**Date** : 2026-08-28
**Tags** : accents, utf-8, hermes, fleet-wide, docker-compose, encoding
**Statut** : valide
---
## Problème
Les 5 conteneurs agents Hermes (hermes-agent-tt, hermes-agent-nyora, hermes-agent-perso sur le NAS ; hermes-nabil et dsh-vps sur le VPS) perdaient tous leurs accents en cours de session — messages Telegram, fichiers écrits, sorties terminal, tout basculait en ASCII pur à un moment donné de l'exécution, y compris du texte déjà correctement accentué plus tôt dans la même session.
## Contexte et contraintes
Lecture directe du code source (`/opt/hermes/agent/conversation_loop.py`, identique dans les 5 conteneurs) : un mécanisme de secours `_force_ascii_payload` (~ligne 4429) se déclenche quand un appel API échoue UNE SEULE fois avec une erreur d'encodage ASCII (`_is_ascii_codec`). Une fois déclenché, le flag reste `True` pour tout le reste de l'exécution de l'agent et `_strip_non_ascii()` (`message_sanitization.py` ligne 336 : `text.encode('ascii', errors='ignore').decode('ascii')`) s'applique à TOUS les appels suivants — irréversible pour la session en cours.
Vérifié sur les 5 conteneurs (`docker exec <c> env | grep -iE "lang|lc_|pythonio|pythonutf"`) : aucun n'avait de variable LANG/LC_ALL/PYTHONIOENCODING/PYTHONUTF8 définie. Sans ça, l'encodage par défaut de Python retombe sur ASCII/C, ce qui rend le déclenchement de `_force_ascii_payload` quasi inévitable dès qu'un caractère accentué traverse un chemin sensible à l'encodage système — fréquent sur une session agentique longue avec beaucoup de tool_calls (le job veille écrit jusqu'à 20 fichiers JSON par run).
## Ce qui NE fonctionne PAS
| Tentative | Erreur obtenue | Raison de l'échec |
|-----------|----------------|-------------------|
| Réécrire le texte accentué à la main dans le prompt/heredoc après le déclenchement | Toujours désaccentué en sortie | `_force_ascii_payload` est un flag persistant pour toute la session — une fois `True`, `_strip_non_ascii()` s'applique même au texte déjà correct ; le contournement doit empêcher le déclenchement en amont, pas corriger après coup |
| Redémarrer le conteneur sans toucher aux variables d'environnement | Le bug revient au prochain déclenchement | Le redémarrage remet juste le flag à `False` — sans fixer l'encodage système par défaut, la première erreur ASCII rencontrée re-déclenche le mécanisme |
## Solution validée
Ajouter ces 4 variables d'environnement dans le `docker-compose.yml` de chacun des 5 conteneurs (`environment:`), puis recréer les conteneurs :
```yaml
LANG: C.UTF-8
LC_ALL: C.UTF-8
PYTHONIOENCODING: UTF-8
PYTHONUTF8: "1"
```
```bash
cd /volume1/docker/hermes-platform && docker compose up -d hermes-agent-tt hermes-agent-nyora hermes-agent-perso
# VPS : même ajout dans /home/claude-oversight/hermes-nabil/docker-compose.yml et /home/dsh-agent/dsh-vps/docker-compose.yml, puis docker compose up -d
```
## Vérification
```bash
for c in hermes-agent-nyora hermes-agent-tt hermes-agent-perso hermes-nabil dsh-vps; do
echo "=== $c ==="; docker exec $c env | grep -iE "lang|lc_|pythonio|pythonutf"
done
# Résultat attendu : les 4 variables présentes sur les 5 conteneurs
```
## Pièges spécifiques DSM / NAS
- Le bug ne se voit qu'APRÈS le premier déclenchement dans une session — un test rapide en début de session peut sembler « propre » alors que le risque reste entier dès qu'un tool_call rencontre un caractère accentué dans un contexte sensible à l'encodage (heredoc, nom de fichier, sortie de commande externe).
- `hermes-nabil` et `dsh-vps` (VPS) sont dans des dépôts Git séparés de `hermes-platform` (NAS) — penser aux deux `git commit`/`push` distincts, pas seulement au commit NAS. Les deux fixes VPS étaient appliqués aux conteneurs en cours d'exécution mais jamais commités jusqu'à vérification explicite après coup.
## Références
- `/opt/hermes/agent/conversation_loop.py` (~ligne 4429, `_force_ascii_payload`)
- `/opt/hermes/agent/message_sanitization.py` (ligne 336, `_strip_non_ascii`)