Cache : corrections de relecture — un rappel de loki ne laisse plus deux messages user d'affilée

Persister les rappels ouvrait trois façons de coller deux `user` dans
l'historique, celles-là même qu'appendNudge voulait éviter : sur un gabarit à
alternance stricte, chaque tour suivant aurait échoué.

- Fin de tour : un rappel resté sans réponse (stop, erreur) ou suivi d'un
  ajout en cours de réponse est retiré avant persistance (dropStrayNudges),
  comme avant sa persistance.
- Compaction : la queue ne commence plus sur un rappel ; la vraie demande
  réinjectée devant elle lui était collée. Elle recule d'un groupe d'outils.
- isLokiInjected ne se contente plus du préfixe « [system] » : un message de
  l'utilisateur qui commence ainsi n'est plus pris pour un rappel (sa demande
  était sautée par la compaction, le vérificateur et le titre).
- Relance tool_choice « none » : pas de repli après un stop, qui partait sur
  un contexte annulé et affichait une erreur.
- Tests : appel par le protocole et refus 4xx sous « none » (et rien
  d'exécuté), frontière de compaction, nettoyage de fin de tour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-04 01:25:39 +02:00
1 parent 38b488515a
commit 9263df404d
6 files changed
+151 -8

No files matched your search

+8 -1
View File
@@ -338,7 +338,14 @@ func compactBounds(msgs []Message, tailBudget int) (head, tailStart int) {
break
}
}
for tailStart > head && msgs[tailStart].Role != "user" && msgs[tailStart].Role != "assistant" {
// Jamais sur un rappel de loki (isLokiInjected) : il a le rôle `user` sans
// être une demande. En tête de queue, la vraie demande réinjectée juste
// avant (pending, voir compactMessages) lui serait collée — deux `user`
// d'affilée, que les gabarits à alternance stricte refusent à chaque tour.
// On recule jusqu'à l'appel d'outil qui le précède : la queue garde un
// groupe de plus, rien n'est perdu.
for tailStart > head && ((msgs[tailStart].Role != "user" && msgs[tailStart].Role != "assistant") ||
isLokiInjected(msgs[tailStart])) {
tailStart--
}
return head, tailStart