Browse Source

EFFORT invalide avec la mémoire : un message clair

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet 9 hours ago
parent
commit
db0e32ad67
3 changed files with 12 additions and 0 deletions
  1. 2 0
      CHANGELOG.md
  2. 2 0
      bot/config.py
  3. 8 0
      tests/test_config.py

+ 2 - 0
CHANGELOG.md

@@ -18,6 +18,8 @@ Les versions les plus récentes sont en haut. Chaque entrée commence par un ré
 
 ### Corrections
 
+- **`EFFORT` invalide avec la mémoire : un message clair.** Avec `MEMORY=on` et la réflexion active (`THINKING=on`, ou un modèle Opus), une valeur inconnue comme `EFFORT=ultra` faisait planter le démarrage avec une trace Python (`KeyError: 'ultra'`) au lieu du message « Erreur de configuration ». La valeur fausse n'est plus réutilisée dans la vérification de `MAX_TOKENS`.
+
 - **Erreurs de démarrage : toutes d'un coup, et dans `bot.log`.** Le bot s'arrêtait à la première variable fausse du `.env` : avec trois erreurs, il fallait trois redémarrages. Il les liste maintenant toutes. Le message n'était écrit que sur la console : il va aussi dans `bot.log` quand `LOG_FILE` est utilisable, pour qu'un redémarrage raté y laisse une trace. Enfin, un PC hors ligne ou une panne de Discord au démarrage donnaient une longue trace technique ; le bot dit maintenant « Impossible de joindre Discord : vérifie la connexion Internet » ou « Discord semble en panne ».
 
 - **Un `.env` entre guillemets marche aussi sous Docker.** `docker run --env-file` garde les guillemets que le bot retire en local : `DISCORD_TOKEN="abc"` donnait « Token Discord invalide » sous Docker. Le bot retire maintenant lui-même une paire de guillemets autour d'une valeur. Le README précise que `--env-file` ne retire pas les commentaires en fin de ligne, et que le `.env` est prioritaire sur une variable passée en ligne de commande.

+ 2 - 0
bot/config.py

@@ -243,6 +243,8 @@ def load_settings() -> Settings:
         effort = effort.lower()
         if effort not in EFFORT_LEVELS:
             errors.append(f"EFFORT doit valoir {', '.join(EFFORT_LEVELS)} (valeur actuelle : {effort!r}).")
+            # memory_max_tokens lit REFLECTION_TOKENS[effort] : une valeur inconnue y lèverait KeyError.
+            effort = None
         # Couper la réflexion n'est accepté qu'avec un effort high ou moins.
         elif thinking_raw == "off" and effort in ("xhigh", "max") and thinking_off(model) is not None:
             errors.append(f"EFFORT={effort} nécessite THINKING=on avec le modèle {model}.")

+ 8 - 0
tests/test_config.py

@@ -108,6 +108,14 @@ class AllErrorsTest(unittest.TestCase):
             settings(MAX_TOKENS="beaucoup", THINKING="oui", EFFORT="max")
         self.assertEqual(len(ctx.exception.errors), 2)
 
+    def test_invalid_effort_with_memory(self):
+        # EFFORT inconnu avec la mémoire : un message clair, pas une KeyError dans memory_max_tokens.
+        for env in ({"THINKING": "on"}, {"CLAUDE_MODEL": "claude-opus-5-5"}):
+            with self.subTest(**env), self.assertRaises(ConfigError) as ctx:
+                settings(EFFORT="ultra", **env)
+            self.assertEqual(len(ctx.exception.errors), 1)
+            self.assertIn("EFFORT doit valoir", str(ctx.exception))
+
     def test_log_file_given_when_usable(self):
         with tempfile.TemporaryDirectory() as folder:
             log = Path(folder) / "bot.log"